T がneverの時の、T extends .. は、問答無用でneverになる
何を言っているか?
tstype A<T> = T extends never ? true : false;
こういう結果になる
tstype B = A<never>; // never
? true : false
だけ見ると、 true
か false
が返ってきそうだが、
何故か never
が返る
ポイント
だとすると、任意の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
...
tstype D<T> = T extends 'a' | 'b' | 'c' ? true : false;
type A = D<'d'>; // false
簡約過程は以下のようになる
tstype A = D<'d'>;
= 'd' extends 'a' | 'b' | 'c' ? true : false;
= false;
'd'
は、 'd'|never
と同じなので、これを D
に適用した結果も同じになるはず
同様に簡約過程を見てみる
tstype 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
と簡約されそう

なぜなら
nerver型はbottom型なので、型引数としなければ、↓のようになる
tstype _ = never extends 'a' | 'b' | 'c' ? true : false; // true
そうなると、②が false|true
となり、
type A = boolean
になって D<'d'>
のときと結果が異なってしまう
例が微妙だったので変えた

↑
ref
ちなみに、型引数にするかどうかで挙動が変わる
直接的に never extends never
と書いた場合は真
tstype A = never extends never ? true : false; // true
型引数にした場合は never
tstype A<T> = T extends never ? true : false;
type B = A<never>; // never
だからこのノートのタイトルには「T がneverの時の、」という条件を入れている
ちなみに、 extends ココ
は何でも良い
どうせ解釈されないので。
だから最初のコード例はこう書いても同じ
tstype A<T> = T extends any ? true : false;
tstype A<T> = T extends string ? true : false;
tstype A<T> = T extends T ? true : false;
...
いずれもこうなる
tstype B = A<never>; // never
当たり前だが、
T
に
never
以外が代入された時の挙動は異なる

意図を明示するために never
と書くのが良いかも
良くないけど。最善策という感じがする

string
とか書くと意図が読み取れない

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