【TypeScript】宣言と型
変数宣言
TypeScript では、JavaScript 同様let
とconst
を用いて変数宣言を行います。
その際に変数の型を指定します。
const n: number = 0
const s: string = 'abcde'
const b: boolean = true
別の型の値を代入するとエラーになります。
let n: number = 0
n = '1' //Type '"1"' is not assignable to type 'number'.
実際のところ、変数宣言の際に必ず型を指定しなければいけないというわけではありません。 初期値に設定したリテラル(値)によって、型推論をしてくれます。
let n = 0 //number
let s = 'abcde' //string
let b = true //boolean
関数宣言
TypeScript では、変数同様に関数の引数と戻り値の型を指定します。
function myFunc(n: number, s: string): string {
return 'abcde'
}
const r: string = myFunc(0, 'abcde')
引数や戻り値に設定した値の型が異なる場合は、エラーとなります。
引数の型を省略した場合はany
という型になります。
戻り値の型を省略した場合は、return
のリテラルによって決まります。
return
がない場合はvoid
となります。
関数式は以下のように宣言できます。
const myFunc: (n: number, s: string) => string = (n: number, s: string) => {
return 'abcde;
}
const r: string = myFunc(0, 'abcde')
型宣言の部分は省略できるのですが、(引数) => 戻り値の型
と指定することは覚えておきましょう。
基本の型
string
JavaScript のString
と同様に文字列を表す型です。
const str1: string = 'abcde'
const str2: string = '12345'
const str3: string = `${str1}fghij`
number
JavaScript のNumber
と同様に数値を表す型です。
整数だけでなく、浮動小数点数や進数もnumber
に含まれます。
const num1: number = 10
const num2: number = 10.102
const num3: number = 0xfff
文字列の数値は代入することができません。
const num: number = '10' //NG
boolean
JavaScript のBoolean
と同様に真偽値を表す型です。
取り得る値はtrue
またはfalse
です。
const bool1: boolean = true
const bool2: boolean = false
array
JavaScript のArray
と同様に配列を表す型です。
型宣言には[]
またはジェネリクス(<>
)を使用します。
const ary1: number[] = [1, 2, 3]
const ary2: Array<number> = [1, 2, 3]
object
JavaScript のObject
と同様にオブジェクトを表す型です。
const obj: object = {
field1: 'val1',
field2: 'val2',
}
object
の他に、{}
を使用することでプロパティとその型を宣言することができます。
ここで宣言していないプロパティへの参照はエラーとなります。
const obj: { id: number; name: string } = {
id: 0001,
name: 'Taro',
}
obj.name = 'Jiro' //OK
obj.age = 20 //プロパティの宣言にないためNG
tuple
tuple
は[]
を使ってデータ構造を表します。
const tuple: [string, number, boolean] = ['abcde', 1, true]
上記の例だと、長さ 3 のstring
、number
、boolean
のデータが順に格納された配列、といったイメージになります。
tuple
へのアクセスは、配列同様インデックスを使用します。
tuple[0] //'abcde'
tuple[1] //1
tuple[2] //true
undefeind / null
TypeScript では、undefined
とnull
に対しても明確に型を指定する必要があります。
const ng: string = undefined //NG
const ok: undefined = undefined //OK
const ng: string = null //NG
const ok: null = null //OK
上記は、TypeScript の設定値であるstrictNullChecks
がtrue
の場合の説明です。
false
に設定すると、ほとんどの型はundefined
やnull
を指定しなくても代入ができるようになります。
しかし、多くの場合はエラーの回避のためにtrue
を使用します。
void
void
は関数やメソッドの戻り値がないことを表すための型です。
通常、変数に設定することはありません。
function doProcess(): void {
//...
}
never
never
はvoid
と似ていて、関数やメソッドの戻り値がないことを表すための型です。
void
との違いは、処理が正常に終了するか否かにあります。
never
は、以下のように処理が最後まで到達することがない場合に使用します。
// 例外スローによって処理が最後まで到達しない
function error(message: string): never {
throw new Error(message)
}
// 無限ループによって処理が最後まで到達しない
function infiniteLoop(): never {
while (true) {}
}
any
any
はすべての型を表します。
つまり、TypeScript の型チェックを無視して代入をすることができます。
しかし、これは TypeScript の恩恵を無視することになるので、型安全を目指すのであれば多用すべきではありません。
let any1: any = 1
any1 = 'abcde'
any1 = true
unknown
unknown
はany
と同じくすべての型を表します。
any
との違いについて、以下の例をみてください。
const a: any = 1
const u: unknown = 1
a.toUpperCase() //実行時エラー
u.toUpperCase() //コンパイル時エラー
数値に対して、大文字に変換するtoUpperCase()
を使用しています。
当然これはエラーになるのですが、そのタイミングが異なります。
any
の場合は、実際に実行した時にエラーが発生します。
一方unknown
は、コンパイル時にエラーとしてくれます。
要は、型がわかっていないのにプロパティ参照やメソッド実行をするな、と事前に通達してくれます。
ユニオン型
TypeScript では、|
を用いることで複数の型を宣言できます。
例えば、以下のようにnumber
とstring
の 2 つの型を持つ変数を宣言できます。
let ns: number | string = 0
n = '1' //これはエラーにならない
現在の値がどの型であるかを調べるために、typeof
を使用します。
const x: number | string = 0
console.log(typeof x) //"number"
リテラル型
TypeScript の型には、文字や数値などのリテラルを指定することができます。 リテラルを指定すると、変数はそのリテラルのみ代入することができます。
let x: 'A' | 'B' = 'A'
x = 'B' //OK
x = 'C' //NG
let x: 0 | 1 = 0
x = 1 //OK
x = 2 //NG
型アサーション
型アサーションとは、不明確な型に対して「これはこの型である」と宣言するためのものです。 そのため型アサーションを行う場合は、プログラマー自身が変数がどの型であるかを把握しておく必要があります。
型アサーションには、as
を使用する方法と<>
を使用する方法があります。
const x: unknown = 'abcde'
const y: string = (x as string).toUpperCase()
const z: string = (<string>x).toUpperCase()