generated at
T がneverの時の、T extends .. は、問答無用でneverになる

何を言っているか?
Conditional Typesを使ったこんな型を定義した時
ts
type A<T> = T extends never ? true : false;
こういう結果になる
ts
type B = A<never>;     // never
? true : false だけ見ると、 true false が返ってきそうだが、
何故か never が返る



ポイント
Distributive Conditional Typesは知っている前提
never は、Conditional Types上では「空のunion」として解釈される
だとすると、任意のunion型は無限に never が続き、無限に分配されることになる
従って、分配過程で登場する never extends .. は問答無用で never を返す



なぜか?
union型内の never は「空のunion型」として扱われる
例えば、
'a' | never は、 'a' になる
'a' | (never | 'b') | (never | never) は、 'a' | 'b' になる
ということは逆に、 'a'|'b' は以下全てと同値
'a'|'b'|never
'a'|'b'|never|never
never|'a'|never|'b'|never|never
...
ここで、以下のようなConditional Typesの簡約を考える
ts
type D<T> = T extends 'a' | 'b' | 'c' ? true : false; type A = D<'d'>; // false
簡約過程は以下のようになる
ts
type A = D<'d'>; = 'd' extends 'a' | 'b' | 'c' ? true : false; = false;
'd' は、 'd'|never と同じなので、これを D に適用した結果も同じになるはず
同様に簡約過程を見てみる
ts
type A = D<'d' | never>; = 'd' extends 'a' | 'b' | 'c' ? true : false | never extends 'a' | 'b' | 'c' ? true : false; // ① = false | never; // ② = false;
D<'d'> と、 D<'d' | never> が同じ結果になるためには、
①の行が、 never に簡約されないと困る
この仕様を知らなければ、①は直感的には true と簡約されそうmrsekut
なぜならnerver型はbottom型なので、型引数としなければ、↓のようになる
ts
type _ = never extends 'a' | 'b' | 'c' ? true : false; // true
そうなると、②が false|true となり、
type A = boolean になって D<'d'> のときと結果が異なってしまう
例が微妙だったので変えたmrsekutref


ちなみに、型引数にするかどうかで挙動が変わる
直接的に never extends never と書いた場合は真
ts
type A = never extends never ? true : false; // true
型引数にした場合は never
ts
type A<T> = T extends never ? true : false; type B = A<never>; // never
だからこのノートのタイトルには「T がneverの時の、」という条件を入れている


ちなみに、 extends ココ は何でも良い
どうせ解釈されないので。
だから最初のコード例はこう書いても同じ
ts
type A<T> = T extends any ? true : false;
ts
type A<T> = T extends string ? true : false;
ts
type A<T> = T extends T ? true : false;
...
いずれもこうなる
ts
type B = A<never>;     // never
当たり前だが、 T never 以外が代入された時の挙動は異なるmrsekut
意図を明示するために never と書くのが良いかも
良くないけど。最善策という感じがするmrsekut
string とか書くと意図が読み取れないmrsekut



では、「型引数 T never である」のような条件分岐を書きたい場合はどうするか?
上の話だと、単純に T extends never ? .. : .. と書くと、 ? 節や : 節に入ってくれない
T[] extends never[] のように書けばいい