ジェネリクスのextends制約を満たさない型を渡すとエラーになる
<T extends { length: number }>のように書くと、Tには「lengthプロパティを持つ型」しか渡せなくなります。制約を満たさない型(例えばnumber)を渡すと、呼び出し時点でエラーになります。
エラーメッセージの読み方
main.ts(4,23): error TS2345: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
main.ts- ファイル名
4- 行番号
23- 列番号 — この位置でtscが検査に失敗しました
TS2345- エラーコード — 検索するとTypeScriptの解説が見つかります
Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.- 内容 — 期待していたもの、または受け付けられなかったもの
このエラーが出る典型パターン
パターン1
1 function getLength<T extends { length: number }>(item: T): number { 2 return item.length; 3 } 4 console.log(getLength(42 )); ^
main.ts(4,23): error TS2345: Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
getLengthはlengthプロパティを持つ型しか受け付けません。numberにはlengthが無いため制約違反になります。
直し方: 42 を "hello" にします。
広告
広告スロット(未設定)
パターン2
1 function printId<T extends { id: number }>(item: T): void { 2 console.log(item.id); 3 } 4 printId("abc" ); ^
main.ts(4,9): error TS2345: Argument of type 'string' is not assignable to parameter of type '{ id: number; }'.
printIdはidプロパティを持つオブジェクトしか受け付けません。文字列にはidがないため制約を満たしません。
直し方: "abc" を { id: 1 } にします。
パターン3
1 function double<T extends { value: number }>(item: T): number { 2 return item.value * 2; 3 } 4 console.log(double(true )); ^
main.ts(4,20): error TS2345: Argument of type 'boolean' is not assignable to parameter of type '{ value: number; }'.
doubleはvalueプロパティを持つ型が必要です。booleanにはvalueが無いため制約に違反します。
直し方: true を { value: 5 } にします。
よくある誤解
「ジェネリクスはどんな型でも受け入れる」という理解は、extends制約を付けていない場合に限った話です。制約を付けた時点で、その形を持たない型は受け付けなくなります。
まとめ
ジェネリクスのextends制約を満たさない型を渡すとエラーになるは上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。