generated at
TypeScriptのあるある部分型の型制約と条件分岐
TypeScriptで型定義する際の extends 周りのあるあるを集めておく
型定義の =
左辺に出てくる extends は、TypeScriptのGenericsの型制約の話
引数に取る型の制約を設ける
他の型システムならkindとか型クラスで制約を設けるが、TSでは部分型 (subtype)でやる
右辺に出てくる extends は、Conditional Typesの条件分岐の話
であることに注意する
両方とも、部分型で同じ話をしているので同じページに書いているmrsekut
これを使いこなすためには、型の階層を把握していないといけないので難易度高いと思うmrsekut




T extends object
record, array, functionを含むことに注意mrsekut


配列である
TS extends unknown[]
tupleは許容しない


TS extends readonly unknown[]
ただの配列は許容しない


関数である
T extends (...args: unknown[]) => unkwnon>
T extends Fucntion
どう違うのかはよくわからん #??
後者のほうが簡潔なので後者で書いているmrsekut


T extends { [K in string]: unknown }
T extends Record<string, unknown>
これは、 {2: boolean, [symbol]: boolean} のように、keyがnumberやsymbolのものも許容するので、直観通り「record」の条件として使える
なんで、numberやsymbolも行けるのかわからん #??
ちなみに、 [K in string] [K in number] に変えても同じになる
なんでかは知らん #??



T[] extends never[]
[T] extends [never]



K extends ${any}



常にtrueを返す
T extends unknown
T exrends any
わざわざこれが必要になるケースは、U extends Uを参照



引数の配列の要素数が1個以上かどうか
いっぱい書き方があるmrsekut
T extends [unknown, ...unknown[]]
例.ts
type Head<T extends unknown[]> = T extends [unknown, ...unknown[]] ? T[0] : never;
T[0] extends T[number]
例.ts
type Head<T extends unknown[]> = T[0] extends T[number] ? T[0] : never
T extends [infer H, ...any[]]
例.ts
type Head<T extends unknown[]> = T extends [infer E, ...any[]] ? E : never;
T extends []
ts
type Head<T extends unknown[]> = T extends [] ? never : T[0];
T['length'] extends 0
ts
type Head<T extends unknown[]> = T['length'] extends 0 ? never : T[0];




共通で持っているpropertyの値を見て絞り込む
ts
type Ts = { kind: 'ts'; hasTypeClass: false }; type Hs = { kind: 'hs'; hasTypeClass: true }; type Purs = { kind: 'purs'; hasTypeClass: true }; type Langs = Ts | Hs | Purs; type HasTypeClass<Lang> = Lang extends { hasTypeClass: true } ? Lang : never; type HasTypeClassLangs = HasTypeClass<Langs>; // Hs | Purs