ts.svg

【TypeScript】宣言と型

TypeScript

変数宣言

TypeScript では、JavaScript 同様letconstを用いて変数宣言を行います。 その際に変数の型を指定します。

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 のstringnumberbooleanのデータが順に格納された配列、といったイメージになります。 tupleへのアクセスは、配列同様インデックスを使用します。

tuple[0] //'abcde'
tuple[1] //1
tuple[2] //true

undefeind / null

TypeScript では、undefinednullに対しても明確に型を指定する必要があります。

const ng: string = undefined //NG
const ok: undefined = undefined //OK
const ng: string = null //NG
const ok: null = null //OK

上記は、TypeScript の設定値であるstrictNullCheckstrueの場合の説明です。 falseに設定すると、ほとんどの型はundefinednullを指定しなくても代入ができるようになります。 しかし、多くの場合はエラーの回避のためにtrueを使用します。

void

voidは関数やメソッドの戻り値がないことを表すための型です。 通常、変数に設定することはありません。

function doProcess(): void {
  //...
}

never

nevervoidと似ていて、関数やメソッドの戻り値がないことを表すための型です。 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

unknownanyと同じくすべての型を表します。 anyとの違いについて、以下の例をみてください。

const a: any = 1
const u: unknown = 1

a.toUpperCase() //実行時エラー
u.toUpperCase() //コンパイル時エラー

数値に対して、大文字に変換するtoUpperCase()を使用しています。 当然これはエラーになるのですが、そのタイミングが異なります。

anyの場合は、実際に実行した時にエラーが発生します。 一方unknownは、コンパイル時にエラーとしてくれます。 要は、型がわかっていないのにプロパティ参照やメソッド実行をするな、と事前に通達してくれます。

ユニオン型

TypeScript では、|を用いることで複数の型を宣言できます。 例えば、以下のようにnumberstringの 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()