こんにちは! 株式会社アルシエで教育に関するサポートをしている岸本です。
今回はTypeScript最終回です。
Conditional Types
Conditional Typesとは、型の条件分岐を行なって型の推論を行うためのものです。
type Props = {
id: string;
name: string;
age: number;
};
上記のコードから、stringのkeyだけを抜き出すコードです。
type FilterString<T> = {
[K in keyof T]: T[K] extends string ? K : never;
}[keyof T];
// keys は "id" | "name"
type keys = FilterString<Props>
1️⃣ まず、<T>にはProps型をジェネリック型パラメータTに代入しています。
2️⃣ [K in keyof T]でPropsの"id" "name" "age"を取得し、
Props型のキー(プロパティ名)を列挙しています。
3️⃣ T[K]は
Lookup Typesです。TがPropsである場合、T['id']はstring、T['name']はstring、T['age']はnumberになります。
4️⃣ extends string ? K : neverについては、
T[K]がstring型に割り当て可能である場合はK、そうでなければneverを返します。
5️⃣ T[K] extends string ? K : never; ←この書き方が
Conditional Typesです。
6️⃣ 最後に[keyof T]ですが、もし記述されてない場合は以下の型になります。
type keys = {
id: "id";
name: "name";
age: never;
}
[ keyof T ]は {} の中にある[K in keyof T]: T[K] extends string ? K : never;
の結果、
type keys = { id: "id"; name: "name"; age: never; } に対して、Lookup Typesがされています。
infer
inferは関数の返り値の型を取得できます。
Tが制約を満たしていれば "U" を返して、満たしていなければ "never" を返します。
barが関数ではない場合は、neverになります。
// bar: () => string の stringだけを抽出したい
const bar = () => {
return ""
}
type Return<T> = T extends () => infer U ? U : never;
// Foo は string型
type Foo = Return<typeof bar>
引数の型だけの取得もできます。
infer Uは引数に記述する事ができます。
引数があり、numberを返す関数であれば "U" を返します。
const bar = (id:string) => {
return 0
}
type Return<T> = T extends (id:infer U) => number ? U : never;
// Foo は string
type Foo = Return<typeof bar>
引数が複数の場合
const bar = (id: string, name: number) => {
return 0;
};
// 残余引数で引数を取得
type Return<T> = T extends (...args: infer U) => any ? U : never;
// Foo は [id: string, name: number]
type Foo = Return<typeof bar>
type Return<T> = T extends (...args: infer U) => any ? U : never;
上記のコードを、毎回記述するのは大変だと思います。そんな時便利なのがUtility Types!
Utility Types
Utility Types
とはコード内で型変換を容易にする為にTypeScriptが提供する(便利な関数のような)型です。
Return
ReturnTypeとするだけで、関数の返り値の型を取得できます。
const bar = (id: string, name: string) => {
return "0";
};
// Foo は string
type Foo = ReturnType<typeof bar>;
Readonly
Readonlyとは全てのプロパティをreadonlyのプロパティにしてくれます。
type Todo = {
title: string
};
const todo: Readonly<Todo> = {
title: '家の掃除',
};
// 読み取り専用プロパティであるため、title に代入することはできません。
todo.title = '夕飯の買い出し';
Partial
Partialは、全てのプロパティをOptionalにします。
type Person = {
firstName: string;
lastName: string;
age: number;
};
const taro: Partial<Person> = {
firstName: "Taro",
};
Required
Requiredは、
全てのプロパティを必須にします。
type Person = {
firstName?: string
lastName?: string
}
// 'lastName' はここで宣言されています。
const jiro: Required<Person> = {
firstName: 'Taro',
}
Pick
Pickは、Pick<T,K>は既に存在するT型の中からKで選択した一部のプロパティのみを含んだ新たな型を構築します。
type Todo = {
title: string
description: string
completed: boolean
}
// type TodoPreview = {
// title: string;
// completed: boolean;
//}
type TodoPreview = Pick<Todo, 'title' | 'completed'>
Omit
Omit<T,K>は既に存在するT型の中からKで選択した一部のプロパティを除いた新たな型を構築します。
type Todo = {
title: string;
description: string;
completed: boolean;
};
// type TodoPreview = {
// description: string;
// }
type TodoPreview = Omit<Todo, "title" | "completed">;
他にも便利なUtility Typesや型を拡張するためのアンビエント宣言・namespaceがありますので、調べてみてください。
TypeScriptに関しては、以上となります。
ご覧いただきありがとうございました!