Wiki_TS_Basic - inoueshinichi/Wiki_Web GitHub Wiki
- ?オプショナルを付加することで, プロパティなしでも動く
function printName(obj: { firstName: string, lastName?: string }) {
....
}
printName({ firstName: 'tiny' })
- プロパティ名やプロパティの数が事前に決まらない場合の型の決め方
{ []: 型名 }
e.g. keyに文字列, オブジェクトに文字列または数値
type Label = {
[key: string]: string | number
}
const labels: Label = {
topTitle: "トップタイトル",
subTitle: "サブタイトル",
statusCode: 200,
status: true, // booleanを定義指定なのでここでエラーが出る
}
(引数名: 型) => 戻り値
function genBirdsInfo(name: string): string[] {
return name.split(',')
}
function singBirds(birdsInfo: (x: string) => string[]) : string {
return birdsInfo('hato,kiji')[0] + 'piyo piyo' // 'hato piyo piyo
}
- TypeScriptが具体的な型を知ることができないケースで使用する.
- e.g. document.getElementById('~')の戻り値の型
- TSは, HTMLElement or null までしかわからない.
- 具体的にHTMLCanvasElementやHTMLDivElementがわからない.
-
変数 = 値 as 型: (開発者は型を知っている)
const myCanvasElem = document.getElementById('main_canvas') as HTMLCanvasElement
- 型アサーションが求められるケース
- より具体的な型へのキャスト
- より汎化される型へのキャスト
型1 -> any -> 型2const user = (response as any) as User
- クラスと親和性が高い拡張ができる
- implementsを用いてクラスに実装を強制できる
- interface定義では, プロパティに?オプショナルにすると強制力がなくなる
interface 型名 {
プロパティ1: 型1
プロパティ2?: 型2
}
e.g.
interface Point {
x: number
y: number
}
function printPoint(point: Point) {
console.log(point)
}
// 拡張
interface Point {
z: number // 追加定義
}
printPoint({ x:100, y:50}) // エラー
printPoint({ x: 1, y: 1, z: 1}) // OK
// 実装の強制
class MyPoint implements Point {
x: number
y: number
z: number // zを消すとエラー
}
// interfaceの?オプショナルによるプロパティの強制力の無効化
interface Matrix {
m11: number
m12: number
m13: number
m14?: number
m21: number
m22: number
m23: number
m24?: number
m31: number
m32: number
m33: number
m34?: number
}
class Matrix3D implements Matrix {
m11: number
m12: number
m13: number
m21: number
m22: number
m23: number
m31: number
m32: number
m33: number
} // OK
- 複数のinterfaceを組み合わせて拡張できる
interface Colorful {
color: string
}
interface Circle {
radius: number
}
interface ColorfulCircle extends Colorful, Circle {}
const cc: ColorfulCircle = {
color: "青",
radius: 1.5
}
// numberベース
enum Direction {
Up = 0,
Down = 1,
Left = 2,
Right = 3
}
// stringベース
enum Direction {
Up = 'Up',
Down = 'Down',
Left = 'Left',
Right = 'Right'
}
class Deque<T> {
private array: T[] = []
popleft(): T {
return this.array.shift()
}
pop(): T {
return this.array.pop()
}
pushleft(item: T): void {
this.array.unshift(item)
}
push(item: T): void {
this.array.push(item)
}
size(): number {
return this.array.length
}
}
const deq: Deque = new Deque<number>()
- 型エイリアス同士の組み合わせ
type Identity = {
id: number | string
name: string
}
type Contact = {
name: string
email: string
phone: string
}
type IdentityORContact = Identity | Contact
// id: number | string
// name: string
// email: string
// phone: string
type Employee = Identity & Contact
// name: string
- 型を文字や数値で指定したもの
変数: 許可するデータ1 | 許可するデータ2 | ...
let postStatus: 'draft' | 'published' | 'deleted'
postStatus = 'draft' // OK
postStatus = 'drafts' // NG
function compare(a: string, b: string): -1 | 0 | 1 {
return a === b ? 0 : a > b ? 1 : -1
}
- 決して発生しない型
- 用途: 常に例外を発生させる抽象基底クラスのメソッドの戻り値などに使用する
function error(message: string): never {
throw new Error(message)
}
function foo(x: string | number | number[]): boolean {
if (typeof x === 'string') {
return true
} else if (typeof x === 'number') {
return false
}
// neverを使用しないとTSコンパイルでエラーが発生する
return error('Never happen')
}
// Enum + Switch + Never
// 将来的にも定数が追加される可能性があるenum型を定義する
enum PageType {
ViewProfile,
EditProfile,
ChangePassword
}
const getTitleText = (type: PageType) => {
switch (type) {
case PageType.ViewProfile:
return 'View'
case PageType.EditProfile:
return 'Edit'
case PageType.ChangePassword:
return 'Change'
default:
// 決して起きないことをTSコンパイラに通達する
const wrongType: never = type
throw new Error(`${wrongType} is not in PageType`)
}
}
- その型が持つ各プロパティの型のUnion型を取得できる
- それは, リテラル型のUnion型
interface User {
name: string
age: number
email: string
}
type UserKey = keyof User;
// UserKey = name | age | email
const key1: UserKey = 'name' // OK
const key2: UserKey = 'phone' // NG
第一引数に渡したオブジェクトの型のプロパティ名のUnion型と 第二引数に渡したオブジェクトの型のプロパティ名のUnion型が 一致しない場合, 型エラーとなる.
function getProperty<T, K extends keyof T>(obj: T, keys: K) T[K] {
return obj[key]
}
- オブジェクトのプロパティが可変の時, まとめて型定義ができる
type SupportVersions = {
[env: number]: boolean
}
let versions: SupportVersions = {
102: false,
103: true,
'v104': true // NG
}
- readonly: クラスやオブジェクトに使う
- const: 変数代入に使う
- Readonly型に型エイリアスを指定するとすべてのプロパティがImmutableになる型が生成できる
type MuttableUser = {
name: string
gender: string
age: number
}
type ImmutableUser = Readonly<MuttableUser>
- anyと同じくどのような型も代入できる
- 代入された値のプロパティにアクセスできない
- typeofやinstanceofと組み合わてunkonw型を具体化して突破する
- unkonwnと型ガードの突破の組み合わせはanyより安全
const x: unkown = 123
console.log(x.toFixed(1)) // NG
// unkownによる型ガードを突破する
if (typeof x === 'number') {
console.log(x.toFixed(1)) // 123.0
}
- Promiseを使う
// Promise<T>
function fetchFromSensor(id: string): Promise<{ success: boolean }> {
return new Promise(resolve => {
setTimeout(() => {
resolve({ success: true })
}, 100) // 100ms後に起動.
})
}
// async/await
async function asyncFunc(): Promise<string> {
const result = await fetchFromSensor('123') // { success: true }
return `The result: ${result}`
}
// 非同期関数の即時実行
(async () => {
const result = await asyncFunc()
console.log(result)
})() // 即時関数
// Promiseとして扱う場合
asyncFunc().then((result) => console.log(result))