🧐
【備忘録】TypeScript - 型推論
Extractをジェネリックな関数で使った時の型推論のプロセス
背景
ジェネリック型の引数を持つ関数でExtractを使用した時のTypeScriptの型推論のプロセスを理解するのに苦労した。
特に以下のgetValues関数のU
がどのように型推論されるのか理解が難しかったため、型推論プロセスを備忘録に残しておく。
例に使うgetValues関数について
第一引数にobject型のobj
、第二引数にobjが持つキーの一部を格納したstring型の配列keys
を持ち、keys
の要素に一致するキーの値を格納したU型の配列を返す。
function getValues<T, U>(obj: T, keys: Extract<keyof T, U>[]): U[] {
return keys.map(key => obj[key]);
}
U
の推論プロセス
sample.ts
function getValues<T, U>(obj: T, keys: Extract<keyof T, U>[]): U[] {
return keys.map(key => obj[key]);
};
const user = {
id: 1,
name: "hoge",
isAdmin: true
};
const values = getValues(user, ["name", "isAdmin"]);
上記のプログラムでは、以下のような推論プロセスでU
が推論される。
-
T
がobj
の型として確定する
obj
にuser
が渡されると、T
は{id: number, name: string, isAdmin: boolean}のオブジェクトリテラル型に基づいて確定される。 - Extract<keyof T, U>の適用
Extract<keyof T, U>が適用されると、keyofT
("id" | "name" | "isAdmin")の中からU
に該当するプロパティ名(["name", "isAdmin"])を抽出するため、keys
の型がT
のプロパティ名と一致することが保証される。 -
U
の初期推論
この時点でU
は"name" | "isAdmin"の文字列リテラルのユニオン型として推論される可能性がある。 -
U
の最終推論
keys.map(key => obj[key]によって、obj[key]の型がU[]の型に割り当てられることになる。つまりU
は["hoge", true]の配列の要素の型、string | booleanとして最終的に推論される。
Discussion