Code Fix

上級

as unknown as Xの二重キャストは型チェックを完全に迂回し、実行時エラーの原因になる

TypeScriptは通常、明らかに無関係な型同士のasによるキャストをエラーにします。しかしunknownを経由する(as unknown as X)と、この安全装置を完全に迂回でき、どんな型にも変換できてしまいます。

エラーメッセージの読み方

main.ts:5
main.ts
ファイル名 — コンパイル前のTypeScriptソースです(sourceMapで変換後の位置を逆引きしています)
5
行番号 — 実際にクラッシュした行
TypeError
例外クラス — 何が起きたか。ここを検索するのが最短です
Cannot read properties of undefined (reading 'toUpperCase')
内容 — 期待していたもの、または受け付けられなかったもの

このエラーが出る典型パターン

パターン1

 1  interface User {
 2    name: string;
 3  }
 4  function greet(u: User): string {
 5    return "Hello, " + u.name.toUpperCase();
 6  }
 7  const raw: number = 42;
 8  console.log(greet(raw as unknown as User));
                                 ^
main.ts:5 TypeError: Cannot read properties of undefined (reading 'toUpperCase')

rawは実際にはnumberです。as unknown as Userは型チェックを完全に迂回するため、実行時にはnameプロパティが存在せずundefinedになります。

直し方: raw as unknown as User{ name: "Al" } にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  function sumAll(items: number[]): number {
 2    return items.reduce((a, b) => a + b, 0);
 3  }
 4  const raw: string = "5";
 5  console.log(sumAll(raw as unknown as number[]));
                                    ^
main.ts:2 TypeError: items.reduce is not a function

rawは実際には文字列です。as unknown as number[]でコンパイラを欺いても、文字列にreduceメソッドは無いため実行時に例外になります。

直し方: raw as unknown as number[][5] にします。

この問題を解いてみる →

パターン3

 1  interface Shape {
 2    describe(): string;
 3  }
 4  function show(s: Shape): string {
 5    return s.describe();
 6  }
 7  const raw: boolean = true;
 8  console.log(show(raw as unknown as Shape      ));
                                   ^
main.ts:5 TypeError: s.describe is not a function

rawは実際にはbooleanです。as unknown as Shapeで型を偽装しても、実行時にはdescribeメソッドが存在せず例外になります。

直し方: raw as unknown as Shape{ describe: () => "a shape" } にします。

この問題を解いてみる →

よくある誤解

「TypeScriptのasは無茶な変換を防いでくれるはず」という安心感は、unknownを経由した二重キャストには通用しません。unknownはあらゆる型からあらゆる型への変換を許すため、安全確認の意味を持たなくなります。

まとめ

as unknown as Xの二重キャストは型チェックを完全に迂回し、実行時エラーの原因になるは上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)