extends
を利用することでジェネリクス(Generics)で引数に制約をつけられます。今回は以下の2つのケースについて紹介します。
- 型の制約をつける場合
- プロパティの制約をつける場合
型の制約をつける場合
ジェネリック関数(ジェネリックメソッド)の引数をstring型もしくはnumber型のみ許可する場合は以下のように記述します。
const returnValue = <T extends number | string>(value: T): T => value;
// stringは number | string の条件を満たすので問題なし
const str = returnValue<string>("hello");
// numberは number | string の条件を満たすので問題なし
const num = returnValue<number>(10);
// booleanは number | string の条件を満たさないのでコンパイルエラーになる
const truthy = returnValue(true);
// Argument of type 'boolean' is not assignable to parameter of type 'string | number'.ts(2345)
console.log(str);
// hello
console.log(num);
// 10
console.log(truthy);
// コンパイルエラー
ジェネリック関数の引数をShape型のみ許可する場合は以下のように記述します。
type Square = {
kind: "square";
size: number;
};
type Rectangle = {
kind: "rectangle";
width: number;
height: number;
};
type Triangle = {
kind: "triangle";
width: number;
height: number;
};
type Shape = Square | Rectangle;
const returnShape = <T extends Shape>(shape: T): T => shape;
const square: Square = { kind: "square", size: 5 };
const triangle: Triangle = { kind: "triangle", width: 5, height: 4 };
// Square型 は Shape型 に含まれているので問題なし
console.log(returnShape<Square>(square).size);
// Triangle型 は Shape型 に含まれているのでコンパイルエラー
console.log(returnShape<Triangle>(triangle).size);
// Type 'Triangle' does not satisfy the constraint 'Shape'.
プロパティの制約をつける場合
例えばsize
プロパティを参照するジェネリック関数を作るとします。その場合、ジェネリクスで定義する型Tにはsize
プロパティが必須になります。
size
プロパティを持つオブジェクトのみジェネリック関数の引数に許可する場合は以下のように記述します。
type Square = {
kind: "square";
size: number;
};
type Rectangle = {
kind: "rectangle";
width: number;
height: number;
};
const getShapeSize = <T extends { size: number }>(shape: T): number =>
shape.size;
const square: Square = { kind: "square", size: 5 };
const rectangle: Rectangle = { kind: "rectangle", width: 5, height: 4 };
// Square には { size: number } が含まれているので問題ない
console.log(getShapeSize<Square>(square));
// 5
// Rectangle には { size: number } が含まれていないのでコンパイルエラーになる
console.log(getShapeSize<Rectangle>(rectangle));
// Property 'size' is missing in type 'Rectangle' but required in type '{ size: number; }'.ts(2344)
参考: Array型の引数のみ許可したい場合
Array型のジェネリック関数を作成する場合は、引数の型をジェネリクスのArray(T[]
)で表現します。extends
の指定は不要です。
具体的には以下のようになります。
const arrayLength = <T>(array: T[]): number => {
// lengthメソッドを実行するので、引数は型Tではなく配列型T[]を指定する必要がある
return array.length;
};
const numberArray = [1, 2, 3];
console.log(arrayLength<number>(numberArray));
// 3
const stringArray = ["a", "b", "c", "d"];
console.log(arrayLength<string>(stringArray));
// 4
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!