generated at
FindFromUnion<R, Key, Value>
recordのunionから1つを抽出する
TypeScriptのrecord型TypeScriptのUnion型から1つのrecordを抽出する





これ、わざざわざ定義しなくてもExtract<U, G>使えば十分mrsekut
以下は同じになる
ts
type A = FindFromUnion<TrafficLight, 'light', 'red'>; type B = Extract<TrafficLight, { light: 'red' }>;









定義
ts
type FindFromUnion< R extends Record<string, unknown>, Key extends keyof R, Value extends R[Key] > = Extract<R, Record<Key, Value>>;


利用例
ts
type TrafficLight = | { light: "red"; action: "stop" } | { light: "yellow"; action: "slow down" } | { light: "green"; action: "go" }; type A = FindFromUnion<TrafficLight, "light", "red">; // { light: "red"; action: "stop" }
union型 TrafficLight から、 light === 'red' なものを抽出している



switch文に型をつける例
ts
export const actionFromLight = <Light extends TrafficLight["light"]>( light: Light ): FindFromUnion<TrafficLight, "light", Light>["action"] => { switch (light) { case "red": return "stop" as any; case "yellow": return "slow down" as any; case "green": return "go" as any; default: return exhaustiveCheck(light); } };
↑型推論の問題で as any を付けないとエラーになる
これ、 TrafficLight の内容が変わった時にエラーにならないので渋い...mrsekut
こうすれば、引数から返り値が決定する
ts
const action = actionFromLight("red"); // 'stop'




定義の意味
Extract<U, G>を応用している
例えば、簡易化した以下のような型を見る
ts
type Red = Extract<TrafficLight, { light: "red" }>; // ↑{ light: "red"; action: "stop" }
これは以下を全て抑えていないと理解できない
Extract<U, G>の定義と意味
ts
type Extract<U, G> = U extends G ? U : never;
U G の部分型なら U を返す
今回は U がUnion型なので、dirstributeして評価される
{ light: "red"; action: "stop" } <: { light: "red"} だということ
従って、
{ light: "red"; action: "stop" } extends { light: "red"} が真となり、
部分型の方である { light: "red"; action: "stop" } が返る