この記事は、かつてTypeScriptで見かける記法が何と呼ぶのかすら分からず困っていた頃の自分へ向けて送るものですが、現在TypeScriptへ入門中の方々にも役立つかなと思い公開する次第です。正確な内容に関してはぜひ公式をご覧ください。
内容の修正や項目の追加などは随時承ります。
Type Annotation
こんな奴
let foo: number
foo = 777 // OK
foo = 'hoge' // コンパイルエラー
日本語での呼び名
- 型注釈
- 型アノテーション
ふわっと紹介
値を初めて定義する際によく使われます。
値に初期値が存在する場合は型推論が働き、let foo = 777
のような宣言でもfoo
の型がnumber型
であることをコンパイラが推定してくれます。初期値の無い宣言で使われることがほとんどですが、_代入時の推論には無理がある場合_などでもちょこちょこ使います。
参考文献
Type Assertion
こんな奴
const foo = <Bar> bar // <Type> value
const foo = bar as Bar // value as Type
-
<Type> value
もしくはvalue as Type
という、式として等価な2通りの記法が存在します。 - 可能ならば_
value as Type
での記述_が推奨されます - _
<Type> Value
での記述_はJSX構文と衝突するためTSXファイルで使用できません
日本語での呼び名
- 型アサーション
ふわっと紹介
型アサーション
は値の持つ型情報を_実行時の値とは別に上書きします_。
_実際の値の型とアサーションの型が確実に一致するとき_以外は使用すべきでありません。
コード付き解説
const element: HTMLElement
// 代入される型を**無視して**`bar`の型が`number型`_となります。
const foo = inputElement as HTMLInputElement
const foo = bar.baz() as string // 2.式の型情報を上書き
const foo = (bar as string).toLowerCase() // 3.括弧によるアサーションの評価順の変更
上記例では、bar
の#baz()
メソッドが返す値とは別に、foo
はstring型
と見做されます。
また、型アサーションは式であるため、括弧によって評価順を変更することも可能です。
例では、bar
の型情報をstring型
に強制しているため、Stringオブジェクトの持つ#toLowerCase()
メソッドが使用可能です。
ここから少し深入りします。
const num = 777
num.toUpperCase() // コンパイルエラー。
#toUpperCase()
メソッドはnumber型
に存在しない、Stringオブジェクトのメソッドであるためコンパイルエラーとなります。というわけで型アサーションを書き加えますが、
const num = 777 as string // コンパイルエラー
num.toUpperCase()
このような、明らかに間違った型によるアサーションもコンパイルで弾かれます。
const num = 777 as any
num.toUpperCase() // コンパイルは成功するものの実行時にエラーが投げられる
まずas any
によりnum
の型はany型
へと上書きされnumber型
ではなくなります。
any型
は任意の型として扱えるので Stringオブジェクトのメソッドである#toUpperCase()
を呼び出すコードがコンパイルでは通りますがしかし、実行時にはエラーを吐きます。any型
の扱いには気をつけましょう。
Generics
こんな奴
Foo<T>
new Foo<Bar>()
foo<Bar>()
日本語での呼び名
- ジェネリック
- ジェネリクス
- (特にを指して)ジェネリック型
ふわっと紹介
例えばArray<T>
という型は「任意で特定の型としてTを内包するArray」という意味になります。
Array型
はそれ自体の定義時にどのような型を内包するのかは不明ですが、実際に使用される際にはインスタンスの内包する型が定まっています。例えばArray<number>
という表記はnumber型
のみで構成されたArrayであるという型を意味します。
つまり、クラスやインターフェイスの宣言時には特定できない、ある時点で判明する型を別途指定するための仕組みがジェネリクスです。
※先述の[Type Assertion](#Type Assertion)とGenericsとは_似て非なる別物_です。ご注意ください。
コード付き解説
Array<T>
やReact.Component<P, S>
などという型として用いられている場合が最初に遭遇するケースとして多いかと思います。
functionでの利用例
// この時点でTは任意の型となり得る。
function toArray<T>(...args: T[]): T[] { return args }
// "words"の型は引数の型から推論され、string[](== Array<string>)となる。
const words = toArray('foo', 'bar', 'baz')
words.push('hoge') // OK
words.push(1) // コンパイルエラー
クラスでの利用例
class MyObject<T> {
members: T[]
constructor(...members: T[]) {
this.members = members
}
pick(index: number): T {
return this.members[index]
}
append(member: T): void {
this.members.push(member)
}
}
// コンストラクタからの型推論によりpick()メソッドの戻り値はstring型となるため、以下のようなチェーンも可能。
const withString = new MyObject('foo', 'bar', 'baz')
const str = withString.pick(1).toUpperCase() // 'BAR'
// 以下の記法は"generic parameter"とも呼ばれ、コンストラクタでは型が指定できない場合などに用いる。
const withNumber = new MyObject<number>()
withNumber.append('foo') // コンパイルエラー
React Component定義での利用例
import React from 'react'
export interface MyProps {
hoge: string
}
export interface MyState {
fuga: string
}
export default class MyComponent extends React.Component<MyProps, MyState> {
/* 任意の実装 */
}
Reactが提供するComponentクラスの場合は継承時にPropsとStateの型が定まるため、実際に使用する際には以下のようなコードになります。
参考文献
- https://www.typescriptlang.org/docs/handbook/generics.html - TypeScript公式
- http://ufcpp.net/study/csharp/sp2_generics.html - C#による解説1
以上、2項目でした。
項目は思いつきor要望があり次第、随時追加予定です。
-
C#の主要開発者であるMicrosoft社はTypeScriptの生みの親 ↩