TypeScriptの型引数にextendsを使用する

に公開

TypeScriptのextendsについての学習のメモ。
※extendsの継承については今回は触れません。

このextendsを使用すれば、型引数に制約をかける事が可能になります。
ではでは順を追って説明していきます。

・型引数を持つ型(ジェネリック型)について

type User<T> = {
  name: string;
  age: T;
};


・型引数に制約をつける

上のUser型はnameはstring型ですが、ageに関しは任意に型を取れるようにしています。
※ 年齢の場合はnumber。年齢を内緒にしたい人のために"secret"のようなstringも取れるようにしています。

ただ上のUser型のままだと、型引数としてnumber、string以外に配列など思わぬ型も許容してしまうことになります。

こういうケースで使用できるのがextendsになります。
上記の型引数にextendsを使用して、制約をつけます。

type User<T extends number | "secret"> = {
  name: string;
  age: T;
};


こうすることでageは"number(実年齢)"か"secret"しか取れなくなります。

また、関数の引数の型に制約をかけることも可能です。

// usernameを返すだけの関数
const getUserName =  <T enxtends User>(user: T) => user.name;


上のようにgetUserNameの引数の前に"TはUserの部分型である"という制約をかけることで、
user.nameがあることを担保することが可能です。
※ 制約なしの<T>のみだとerrorになります。

・conditonal Typesにextendsを使用する

conditional Typesでextendsを使用する際は以下のような構文を取ります。

X enxtends Y ? S : T


これは"XがYの部分型であればSになり、そうでなければTをとるといった意味になります。
具体的に見ていきます。

// TがnumberならNameOrIdは、IdLabel 
// TがsringならNameorIdは、NameLabel

type NameOrId<T extneds number | string> = T extends number ? IdLabel : NameLabel;


このように Tがstringの部分型かnumberの部分型かによって、NameOrIdの型が変化するものができます。
こちらはユニオン型を使用して、"どっちの部分型か?"のチェックをしていますが、下記のように"指定した型の部分型かどうか?(条件を満たしているか)"のパターンにも使用されます。

type Animal = {
  name: string;
};

type Human = {
  name: string;
  language: string;
};

type U = Human extends Animal ? true : false; 
// type U: true; になります


Human型はAnimal型の部分型になるのでUはtrueになります。