ジェネリクスとは
型を引数として受け取ることができる。同じ処理を違う型で実行する際に便利。
下記の記事が非常にわかりやすい。
function copy<T>(value: T): T {
let user: T;
return value;
}
console.log(copy<string>('hello').toUpperCase);
console.log(copy<number>(6).valueOf);
copy()の引数や戻り値をstringかnumberか指定して実行することができる。
下のようにオブジェクトを引数として取る場合、ジェネリクスを省略してもnameプロパティを使用することができる。
name: stringのオブジェクトだと型推論してくれる。
// 厳密にはこう
console.log(copy<{name: string}>({name: 'Quill'}).name);
// こっちでもOK
console.log(copy({name: 'Quill'}).name);
型パラメータに制約をつける
より厳密に制約を設ける場合はextendsを使用する。
function copy<T extends {name: string}>(value: T): T {
let user: T;
return value;
}
console.log(copy({name: 'Quill'}).name);
keyof演算子
keyof演算子を使うことでオブジェクトプロパティのキーのユニオン型を作ることができる
type K = keyof { name: string; age: number }
type K = "name" | "age"
function copy<T extends {name: string}, U extends keyof T>(value: T, key: U): T {
value[key];
return value;
}
console.log(copy({ name: 'Quill', age: 38 }, 'name'));
U extends keyof Tは「オブジェクトTのキー」をUとして定義している
クラスへジェネリクスを使用する
class LightDatabase<T extends string | number | boolean> {
private data: T[] = [];
get() {
return this.data;
}
}
const stringLightDatabase = new LightDatabase<string>();
stringLightDatabase.get();
インターフェースにジェネリクスを使用する
interface TmpDatabase<T> {
id: number;
data: T[];
}
const TmpDatabase: TmpDatabase<number> = {
id: 3,
data: [32]
}
Utility型
interface Todo {
title: string;
text: string;
}
type Todoable = Partial<Todo>
type ReadTodo = Readonly<Todo>
型
type Todoable = {
title?: string | undefined;
text?: string | undefined;
}
type ReadTodo = {
readonly title: string;
readonly text: string;
}
配列の型を定義する際はジェネリック型のArrayを使うことができる。
Arrayなどのジェネリック型はTypeScriptに内蔵されている。
const vegetables: Array<string> = ['Tomato', 'Broccoli'];
型パラメータにデフォルト値を設定する
interface ResponseData<T extends { message: string } = any> {
data: T;
status: number;
}
let tmp2: ResponseData;
Mapped Types
inを使うことでfor文で型を扱える。
ハイフン-をつけるとVegetablesインターフェースでtomatoに指定していたreadonlyをMappedTypesでは無効化することができる。
interface Vegetables {
readonly tomato: string;
pumplin?: string;
}
let tmp3: keyof Vegetables;
type MappedTypes = {
-readonly [P in keyof Vegetables]?: string
}
Conditional Types
三項演算子のようなものを使用することで型のif文を定義することができる。
type ConditionalTypes = 'tomato' extends string ? number : boolean;
let aa: ConditionalTypes; // number型
type ConditionalTypes2 = string extends 'tomato' ? number : boolean;
let bb: ConditionalTypes2; // boolean型