型推論

TypeScriptでは、明示的な型注釈がない場合に型情報を提供するために、型推論がいくつかの場面で使用されます。例えば、以下のコードでは

ts
let x = 3;
let x: number
Try

x変数の型はnumberと推論されます。この種の推論は、変数とメンバーの初期化、パラメータのデフォルト値の設定、関数の戻り値の型の決定時に行われます。

ほとんどの場合、型推論は簡単です。以下のセクションでは、型がどのように推論されるかについて、いくつかのニュアンスを探ります。

最良の共通型

複数の式から型推論を行う場合、それらの式の型を使用して「最良の共通型」が計算されます。例えば、

ts
let x = [0, 1, null];
let x: (number | null)[]
Try

上記の例でxの型を推論するには、各配列要素の型を考慮する必要があります。ここでは、配列の型としてnumbernullの2つの選択肢が与えられています。最良の共通型アルゴリズムは、各候補型を検討し、他のすべての候補と互換性のある型を選択します。

最良の共通型は、提供された候補型から選択する必要があるため、型は共通の構造を共有するものの、どの型もすべての候補型のスーパータイプではない場合があります。例えば

ts
let zoo = [new Rhino(), new Elephant(), new Snake()];
let zoo: (Rhino | Elephant | Snake)[]
Try

理想的には、zooAnimal[]と推論されることが望ましいですが、配列内に厳密にAnimal型のオブジェクトがないため、配列要素の型については推論を行いません。これを修正するには、どの型も他のすべての候補のスーパータイプでない場合に、明示的に型を指定します。

ts
let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
let zoo: Animal[]
Try

最良の共通型が見つからない場合、結果の推論はユニオン配列型である(Rhino | Elephant | Snake)[]になります。

コンテキスト型付け

TypeScriptでは、場合によっては型推論が「逆方向」にも機能します。これは「コンテキスト型付け」と呼ばれます。コンテキスト型付けは、式の型がその場所によって暗示される場合に発生します。例えば

ts
window.onmousedown = function (mouseEvent) {
console.log(mouseEvent.button);
console.log(mouseEvent.kangaroo);
Property 'kangaroo' does not exist on type 'MouseEvent'.2339Property 'kangaroo' does not exist on type 'MouseEvent'.
};
Try

ここで、TypeScript型チェッカーは、`Window.onmousedown`関数の型を使用して、代入の右辺にある関数式の型を推論しました。そうすることで、MouseEvent型の`mouseEvent`パラメータの型を推論することができ、これには`button`プロパティは含まれていますが、`kangaroo`プロパティは含まれていません。

これは、windowがすでに型で`onmousedown`を宣言しているため機能します。

ts
// Declares there is a global variable called 'window'
declare var window: Window & typeof globalThis;
// Which is declared as (simplified):
interface Window extends GlobalEventHandlers {
// ...
}
// Which defines a lot of known handler events
interface GlobalEventHandlers {
onmousedown: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null;
// ...
}

TypeScriptは、他のコンテキストでも型を推論するのに十分なほどスマートです。

ts
window.onscroll = function (uiEvent) {
console.log(uiEvent.button);
Property 'button' does not exist on type 'Event'.2339Property 'button' does not exist on type 'Event'.
};
Try

上記の関数が`Window.onscroll`に代入されているという事実から、TypeScriptは`uiEvent`がUIEventであり、前の例のようなMouseEventではないことを認識しています。`UIEvent`オブジェクトには`button`プロパティが含まれていないため、TypeScriptはエラーをスローします。

この関数がコンテキスト型付けされた位置にない場合、関数の引数は暗黙的にany型となり、エラーは発生しません(noImplicitAnyオプションを使用している場合を除く)。

ts
const handler = function (uiEvent) {
console.log(uiEvent.button); // <- OK
};
Try

コンテキスト型をオーバーライドするために、関数の引数に明示的に型情報を指定することもできます。

ts
window.onscroll = function (uiEvent: any) {
console.log(uiEvent.button); // <- Now, no error is given
};
Try

ただし、uiEventにはbuttonというプロパティがないため、このコードはundefinedをログに記録します。

コンテキスト型付けは多くの場合に適用されます。一般的なケースとしては、関数呼び出しの引数、代入の右辺、型アサーション、オブジェクトおよび配列リテラルのメンバー、return文などがあります。コンテキスト型は、最良共通型における候補型としても機能します。例えば、

ts
function createZoo(): Animal[] {
return [new Rhino(), new Elephant(), new Snake()];
}
Try

この例では、最良共通型には4つの候補があります。AnimalRhinoElephant、およびSnakeです。これらのうち、最良共通型アルゴリズムによってAnimalが選択されます。

TypeScriptのドキュメントはオープンソースプロジェクトです。プルリクエストを送信して、これらのページの改善にご協力ください

このページへの貢献者
RCRyan Cavanaugh (51)
OTOrta Therox (17)
DRDaniel Rosenwasser (10)
MHMartin Hanzel (2)
TLATThink Like a Techy (1)
12+

最終更新日: 2024年3月21日