TypeScriptの型について自分が勉強したことをまとめます。
TypeScriptの型(基本)
TypeScriptを使う上でこれは必ず理解しておきたいという基本的な型についてまとめます。
string
文字列しか受け付けなくなる。
const name: string = '太郎' // OK
const name: string = 100 // NG
number
数字しか受け付けなくなる。
const age: number = 30 // OK
const age: number = '30' // NG
boolean
真偽値(true or false)しか受け付けなくなる。
const isAdmin: boolean = true // OK
const isAdmin: boolean = 'true' // NG
もちろん0 = false
、1 = true
という判定もしてくれないです。
const isAdmin: boolean = 0 // NG
const isAdmin: boolean = 1 // NG
null
nullしか受け付けなくなる。
const nullConst: null = null // OK
const nullConst: null = 'null' // NG
undefined
undefinedしか受け付けなくなる。
const undefinedConst: undefined = undefined // OK
const undefinedConst: undefined = 'undefined' // NG
any
どんな型のデータも受け付ける。
// 全部OK
const any1: any = '文字列'
const any2: any = 100
const any3: any = false
const any4: any = null
const any5: any = ['リンゴ', 'バナナ', 'オレンジ']
any
型はどんな型に受け付けるので、TypeScriptを使う意味がないです。
以下のようなケースで使うことが望ましい。
- JavaScript→TypeScriptのリプレイスの初期段階
- まずは暫定でany型で型定義してリプレイスを進めていく中で少しずつ減らす
- 最終的には0にする
- 型がまだ確定できない時
- 必ずコメントを残して最終的に残らないようにする
配列
配列型の定義の仕方は2つあります。
// 1. Array<type>
// ジェネリクスという機能を使う
const array1: Array<number> = [1, 2, 3, 4, 5]
// type[]
let array2: number[] = [1, 2, 3, 4, 5]
上記のようにArray<number>
もしくはnumber[]
とすることで「数字の配列」型になるので、文字列の要素を追加したり配列以外の型のデータを格納しようとするとエラーになります。
const array1: Array<number> = [1, 2, 3, 4, 5]
// NG
array1.push('string')
let array1 = 100
オブジェクト
オブジェクト型は各プロパティー(キー+バリュー)の型(キーの名前、バリューのデータ型)を定義できます。
// nameには文字列、ageには数字が入るオブジェクト
const obj: { name: string, age: number } = {
name: '太郎',
age: 30
}
obj
が持てるキーはname
、age
だけなので型定義にないキーのプロパティを持つことはできないです。
// エラー
const obj: { name: string, age: number } = {
name: '太郎',
age: 30,
isAdult: true
}
逆も然りです。
// エラー
// isAdultを持たないといけないのにobjには定義されていない
const obj: { name: string, age: number, isAdult: boolean } = {
name: '太郎',
age: 30,
}
オブジェクト型は型定義の部分は長くなってしまうことが多々あるのでtype
を使って型定義を切り出すのも有効。
// これまでのようにそのまま定義すると見づらい...
const obj1: {
name: string,
age: number,
isAdult: boolean,
country: string,
hobbies: Array<string>
} = {
name: '太郎',
age: 30,
isAdult: true,
country: Japan,
hobbies: ['筋トレ', '料理', '買い物']
}
// typeを使って型定義を切り出す
// typeを定義
type Obj = {
name: string,
age: number,
isAdult: boolean,
country: string,
hobbies: Array<string>
}
const obj2: Obj = {
name: '太郎',
age: 30,
isAdult: true,
country: Japan,
hobbies: ['筋トレ', '料理', '買い物']
}
個人的には後者のtype
を使った定義を仕方をよく使います。
関数
関数の型定義は引数、返り値それぞれでできます。
型定義を省略した場合は以下のような扱いになります。
- 引数:any型として扱われる
- 返り値:コンパイラが型推論する
引数の型定義に関してはTypeScriptの設定内容を定義するtsconfig.json
のnoImplicitAny
をtrue
に設定することで指定を必須にする(any
型を許容できなくする)ことができます。
関数の型定義の方法は以下のとおり。
// 引数に数字、返り値に数字の型定義
// アロー関数
const func1 = (num: number): number => num + 1
// アロー関数を使わない
const func1 = function (num: number): number {
return num + 1
}
// 何も返さない時はvoid
const func2 = (num: number): void => console.log(num + 1)
上記で定義したfunc1
自体の方は以下となります。
const func1: (num: number) => number
その他
他にも
- symbol型
- bigint型
- never型
などの型がありますが、僕は使ったことがないので省略。
(never型については後ほど少しだけ触れます)
TypeScriptの型(ちょっと応用)
ここまでにまとめた基本的な型が理解できた後に理解したい型をまとめます。
(ただいきなりTypeScript未経験の状態でTypeScriptを使っているPJに入った場合は同時並行で理解していく必要があります。ちなみにそれ僕です。)
intersection型(交差型)
2つの型を合わせてできた型のことです。
以下のコードのように&
を使うことで新しい方を作ります。
// 直で書く
const obj: { name: string } & { age: number } & { isAdult: boolean } = {
name: '太郎',
age: 30,
isAdult: true
}
// これと同じになる
const obj: { name: string, age: number, isAdult: boolean } = {
name: '太郎',
age: 30,
isAdult: true
}
まあ正直上記のように1つの1つを合体させるのは効果的ではないので、実際にはこんな感じでtype
を混ぜて使うことが多いと思います。
type Type1 = {
name: string
age: number
}
type Type2 = {
name: string
isAdult: boolean
}
// &で新しい型Type3を作る
type Type3 = Type1 & Type2
const obj1: Type3 = {
name: '太郎',
age: 30,
isAdult: true
}
// これでもOK
const obj2: Type1 & Type2 = {
name: '太郎',
age: 30,
isAdult: true
}
Type1とType2でname: string
が共通しているのでマージされます。(=1つとしてカウントされる)
intersection型を使う時の注意点は実際にはあまり発生しないかもですが、キーが同じでバリューの型が違うオブジェクトの型を合体させる時かなと思います。
type Type1 = {
name: string
age: number
}
type Type2 = {
name: number // Type1ではstring型
isAdult: boolean
}
// &で新しい型Type3を作る
type Type3 = Type1 & Type2
const obj: Type3 = {
name: '太郎', // Type 'string' is not assignable to type 'never'. となりエラー
age: 30,
isAdult: true
}
片方がname: string
、片方がname: number
となっており、これを合体するとname: never
になってしまいます。
never型は値を持たない型なので、ここで新しく作ったType3の型定義をしたオブジェクトのnameプロパティにどんな値を入れてもエラーになります。つまり使うケースがない型です。

union型(合併・共用体)
複数の型を許容する型です。
よくある「AまたはB」で、|
を使います。
// val1は文字列、数字どちらでも許容される
const val1: string | number = '太郎' //OK
const val2: string | number = 1000 //OK
const val3: string | number = false // NG
// undefinedやnullと一緒に使うことが多い(気がする)
const val4: string | null = '太郎'
// typeを使うこともできる
type Type1 = string | number
// |を使うことで string | number | null の型として扱える
const val5: Type1 | null = 1000
Utility型(ユーティリティ型)
ユーティリティ型は直感的には理解しにくい印象ですが、TypeScriptの組み込み機能であり以下の記事では「コード内で型変換を容易にする為にTypeScriptが提供する(便利な関数のような)型達」と書かれています。

上記記事を見るとわかりますが、ユーティリティ型は結構な量があるので全部は書きませんがオブジェクトの型に関係するものを3つピックアップします。
Partial<T>
T
に指定するオブジェクト型の全てのプロパティを省略可能な型を生成するものです。
(ここもジェネリクスを使っているのでジェネリクスは別の記事にまとめます)
// 型定義
type User = {
name: string
age: number
isAdult: boolean
}
// age, isAdultのプロパティがないけど問題ない
const obj: Partial<User> = {
name: '太郎'
}
// Partial<User>はこのような型になる
type Partial<User> = {
name?: string
age?: number
isAdult?: boolean
}
// キー名?で省略可能となりこれと同じ意味を持つ
type Partial<User> = {
name: string | undefined
age: number | undefined
isAdult: boolean | undefined
}
obj
はキーがname
のプロパティしか持っていないですが、エラーにはなりません。
Readonly<T>
T
に指定するオブジェクト型の全てのプロパティを読み取り専用(上書き不可)な型を生成するものです。
// 型定義
type User = {
name: string
age: number
isAdult: boolean
}
const obj: Readonly<User> = {
name: '太郎',
age: 30,
isAdult: true
}
// 読み取り専用なので上書きできない
obj.age = 35 // Cannot assign to 'age' because it is a read-only property.
// Readonly<User>はこのような型になる
type Partial<User> = {
readonly name: string
readonly age: number
readonly isAdult: boolean
}
readonly
プロパティをつけることで上書き(更新)できなくなります。
Required<T>
T
に指定するオブジェクト型の全てのプロパティを必須な型を生成するものです。
// 型定義
type User = {
name: string
age: number
isAdult: boolean
}
// age, isAdultのプロパティがないけど問題ない
const obj: Required<User> = {
name: '太郎',
age: 30,
isAdult: true
}
// isAdultは必須なのでエラーになる
// Property 'isAdult' is missing in type '{ name: string; age: number; }' but required in type 'Required<User>'.
const obj2: Required<User> = {
name: '太郎',
age: 30
}
明示的に必須という条件をつけることができます。
Record<Keys, Type>
キーがKeys
であり、プロパティの値がType
であるオブジェクト型を作ります。
const obj1: Record<string, number> = {
a: 10,
b: 100,
c: 1000
}
const obj2: Record<'key1' | 'key2' | 'key3', string> = {
key1: 'value1',
key2: 'value2',
key3: 'value3'
}
もちろん|
(union型)を使ってkeyを制限することもできます。
最後に
TypeScript(というか静的型付言語)では色々な型が用意されているのでいきなり全部覚えるのは大変です。
実際にコードを書きながら体に慣らしていくのが良いと思います。
参考記事


コメント
コメント一覧 (1件)
[…] yutaro blog | 【TypeScript】型について(基礎〜ちょっと応用) | yutaro blog Jav… […]