おかえり never のもりへ
こんにちは
型のくにからこんにちは。
最近型レベルプログラミングにハマりつつある yossuli です。
#1 日 1Zenn はちょっと無茶があり期間があいてしまいましたが、前回触れた never
の特殊?な挙動についてまとめていきます。
any でも unknown でもない、そのあいだのなめらかなゆめ
never
とは型システムを集合論としてとらえたときに「空集合」を表す型です。
空集合であるがゆえに、never
には代入することはできず、逆に never
は型レベルではどんな型にも代入可能です。
declare const never: never;
declare const any: any;
declare const string: string;
// OK
const a: never = never;
const b: any = never;
const c: string = never;
// Error
const d: never = any;
const e: never = string;
ただし、never
型の値は存在しないため、never
は型レベルでどんな型にでも代入可能であることには意味がありません。
おかえり never のもりへ
never
が型レベルで空集合であることにどのような意味があるのか、実際のコードを見ていきましょう。
前提知識
まず、never
が空集合であることがどのように役立つのかを理解するために、conditional type
の挙動について確認しておく必要があります。
一般的な挙動については省略して、extends
句の左辺にユニオン型が来た場合の挙動を見ていきます。
type Conditional<T> = T extends string ? "string" : "other";
// Conditional<string | number>
// => "string" | "other"
このように、extends
句の左辺にユニオン型が来た場合、ユニオンの各要素に対して条件を評価し、結果をユニオンとして返します。
ユニオンとして解釈されたくない場合は []
で両辺を囲むことで回避できます。
ユニオンから特定の型を除外する
type Exclude<T, U> = T extends U ? never : T;
// Exclude<string | number, string>
// => never | number
// => number
// Exclude<string | number | boolean, string | boolean>
// => never | number | never
// => number
このように、特定の型に対して never
を返すことで、never
が空集合であることを利用して、ユニオン型から特定の型を除外することができます。
マッピング型から特定のプロパティを除外する
type Omit<T, K extends keyof T> = {
[P in keyof T as P extends K ? never : P]: T[P];
};
// Omit<{ a: string; b: number; c: boolean }, "b">
// => { a: string; never: string; c: boolean }
// => { a: string; c: boolean }
このように、プロパティを never
にすることで、never
が空集合であることを利用して特定のプロパティを除外することができます。
人はいろいろなものに名前を付けました
あくまで never
は型レベルで空集合を表す名前です。
僕のように never
に対して存在する型として扱わないように...
さようなら
なんか never
って null
より null
らしいなというところから書き始めた駄文でしたがお付き合いいただきありがとうございました。
null² は素晴らしいパビリオンなので是非訪れてみてください。
Discussion