はじめに
今回は 型修飾子 についてまとめております。
【目次】
まずは基本的な型宣言をマスターしよう!
オブジェクト型の型宣言をマスターしよう!
関数の型定義をマスターしよう!
配列をマスターしよう!
インターフェースをマスターしよう!
クラスを使いこなそう!
型修飾子についての理解を深めよう! ←🈁
ジェネリックをマスターしよう!
独自の構文拡張をマスターしよう!
トップ型
全てのデータを割当できるデータ型です。
any
unknown
any
指定することでTypeScriptによる型チェックが行われなくなります。
型チェックの恩恵が失われてしまうので、なるべく利用しないようにしましょう。
function fn(input: number) {
// NG: Property 'toUpperCase' does not exist on type 'number'.
input.toUpperCase()
}
function anyFn(input: any) {
// OK
input.toUpperCase()
}
unknown
全てのオブジェクトを割り当てることが可能
any
との違いは unknown
型のメンバーに直接アクセスすることが禁止されているということです。
サンプルコードを見ていきましょう.
function fn(input: unknown) {
// NG: 'input' is of type 'unknown'.
input.toUpperCase();
}
inputに対して、
toUpperCase()`を実行した際に型エラーが発生しています。
typeof
, instanceof
などで対象の型を絞り込むことでメンバーへのアクセスが可能です。
function fn(input: unknown) {
if(typeof input === "string") {
input.toUpperCase();
}
}
上記理由から、any
よりもunknown
を優先的に利用しましょう。
ユーザー定義型ガード
TypeScriptでは、引数が特定のデータ型を返すか関数のためのユーザー定義型ガードが用意されています。
以下のサンプルコードを見ていきましょう。
function isString(input :unknown) {
return typeof input === "string"
}
function toUpperCaseIsString(input: string | number) {
if(isString(input)) {
// NG: Property 'toUpperCase' does not exist on type 'string | number'.
console.log(input.toUpperCase())
}
}
input.toUpperCase()
で型エラーが発生しています。
我々開発者はisString(input :unknown)
が、引数がstring
型であればtrue
を返すことをすぐ認識できますが、TypeScriptはそうではありません。
以下のように関数パラメータの後に引数の戻り値を指定する必要があります。
これで型エラーが解消されます。
function isString(input :unknown): input is string {
return typeof input === "string"
}
function toUpperCaseIsString(input: string | number) {
if(isString(input)) {
// OK
console.log(input.toUpperCase())
}
}
keyof
keyof
はオブジェクトのキーの合併型を作成します。
以下のサンプルコードでは、key
がfirst
, second
以外の値を取りうることができるため、型エラーが発生します。
interface ScoreObj {
first: number
second: number
}
function getScore(score: ScoreObj, key: string){
//NG: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'ScoreObj'.
console.log(score[key])
}
keyof
を使用することで型エラーが解消されます。
interface ScoreObj {
first: number
second: number
}
function getScore(score: ScoreObj, key: keyof ScoreObj){
console.log(score[key])
}
この場合、key
はScoreObj
キーの合併型("first" | "second"
)と評価されます。
typeof
typeof
は与えられた値の型を返します。
const hasNameAge = {
name: "taro",
age: 30
}
let person: typeof hasNameAge;
上記の宣言は、以下のように宣言と同意義です。
コードがスッキリしますね。
let person: {
name: string;
age: number;
}
typeof + keyof
typeof
と keyof
を活用することで特定のオブジェクトのキーの合併型を簡単に定義できます。
let sampleObj = {
value1: 100,
value2: 500,
}
function getObjectValue(key: keyof typeof sampleObj) {
console.log(sampleObj[key]);
}
//OK
getObjectValue("value1")
getObjectValue("value2")
//NG: Argument of type '"value3"' is not assignable to parameter of type '"value1" | "value2"'.
getObjectValue("value3")
型キャスト
型キャスト を利用することでTypeScriptによる型解釈を上書きすることが出来ます。
ユースケース
基本的に型キャストの利用は推奨されませんが、JSON.parse
のようにトップ型(any
)を返すメソッドがあります。
戻り値のデータ型を予め定義できる場合は、以下のように型キャストを使用します。
const data = `["hoge", "foo"]`;
// OK: any
let anyData = JSON.parse(data);
// OK: string[]
let stringArg = JSON.parse(data) as string[];
// OK: [string, string]
let StringTuple = JSON.parse(data) as [string, string];
非nullアサーション
変数の値として null, undefined
があり得るものの、実際のデータはそうでないことが確証できることがあります。
データから null, undefined
を取り除く「!
」がTypeScriptには用意されています。
const sampleMap = new Map([
[1, "first"],
[2, "second"]
])
sampleMap.get(2)!.toUpperCase();
sampleMap.get(2)
は string | undefined
ですが、
sampleMap.get(2)!
として実行することで値がstring
型として上書きされています。
そのため、型エラーが発生することなく、toUpperCase()
を実行できます。
const
TypeScriptには const
アサーションが用意されており、指定した値を不変として扱います。
constアサーションはデータ型ごとに異なる振る舞いをします。
- 配列
- 配列を
readonly
のタプル型として扱う
- 配列を
- リテラル
- 一般的なプリミティブ型ではなく、リテラル型として扱う
- オブジェクトプロパティ
-
readonly
として扱う
-
サンプルコードを見ていきましょう。
配列
// let args: string[]
let args = ["value1", "value2"];
// let argsAsConst: readonly ["value1", "value2"]
let argsAsConst = ["value1", "value2"] as const;
リテラル
// let one: number
let one = 1;
// let oneAsConst: 1
let oneAsConst = 1 as const;
オブジェクト
const sampleObj = {
name: "Taro",
age: 25
}
/*
const sampleObj: {
name: string;
age: number;
}
*/
const sampleObjAsConst = {
name: "Taro",
age: 25
} as const
/*
const sampleObjAsConst: {
readonly name: "Taro";
readonly age: 25;
}
*/
特定のライブラリなどで、フィールドが特定のリテラル型を求める場合があります。
その際は as const
キーワードを使用するようにしましょう。
まとめ
以上です〜
次の記事ではジェネリック型についてまとめる予定です。