TypeScript Handbook を読み進めていく第八回目。
- Basic Types
- Variable Declarations
- Interfaces
- Classes
- Functions
- Generics
- Enums
- Type Inference (今ココ)
- Type Compatibility
- Advanced Types
- Symbols
- Iterators and Generators
- Modules
- Namespaces
- Namespaces and Modules
- Module Resolution
- Declaration Merging
- JSX
- Decorators
- Mixins
- Triple-Slash Directives
- Type Checking JavaScript Files
Type Inference
Basics
TypeScript では、型が明示されていない場合に型推論が行われるところが何箇所かあります。
以下の例では x
の型は number
と推論されます。
let x = 3;
このタイプの推論は、変数やメンバの初期化時、デフォルト引数の設定時、関数の戻り値の型の決定時に行われます。
Best common type
複数の式に対して型推論が行われる場合、それらの式の "最適な共通型" が型として採用されます。
以下の例では、配列の各要素の型を基に x
の型が推論されますが、各要素の型として number
または null
が考えられます。
let x = [0, 1, null];
--strictNullChecks
を指定していない場合、null
をnumber
に代入できるのでx
の型はnumber[]
になる。
--strictNullChecks
を指定している場合、null
をnumber
に代入できないため、x
の型は(number|null)[]
になる。
最適な共通型は指定された型を基に選択されるため、以下の例では zoo
の型が Animal[]
として推論されてほしいと思うかもしれませんが、実際には各要素が Animal
を継承したクラスではないのでそのようには推論されません。
let zoo = [new Rhino(), new Elephant(), new Snake()];
これを修正するためには型を明示することです。
let zoo: Animal[] = [new Rhino(), new Elephant(), new Snake()];
まあ意図しない推論を予防するためにも、なるべく型は指定した方が良いだろうね
そして、最適な共通型が見つからなかった場合には共用配列型 ((Rhino | Elephant | Snake)[]
) が採用されます。
any
とかになるわけではないのね
Contextual Type
TypeScript は他にも "文脈に基づく型付け" と呼ばれる推論も行いますが、これは型推論が行われる場所に基づいて行われます。
以下の例はエラーになりますが、これは右辺が Window.onmousedown
に代入可能な関数であることに基づいて、mouseEvent
引数の型が自動的に推論されるためです。
window.onmousedown = function(mouseEvent) {
console.log(mouseEvent.buton); //<- エラー。正しくは 'button'
};
ただし、明示的に型が指定されている場合には、文脈に基づく型付けは行われません。
window.onmousedown = function(mouseEvent: any) {
console.log(mouseEvent.buton); //<- エラーにならなくなる
};
文脈に基づく型付けは、最適な共通型の候補にもなります。
以下の例では最適な共通型として、Animal
、Rhino
、Elephant
、Snake
の中から Animal
が選択されます。
function createZoo(): Animal[] {
return [new Rhino(), new Elephant(), new Snake()];
}
戻り値の型を明示してるけど、例として正しいんだろうか?