今回はTypeScriptで最も重要となる「型の基礎」について説明していきたいと思います。ここでの「型」とは、データの性質のようなもので、どのように取り扱うべきかの定義だと考えてもらえばいいかと思います。
以下、TypeScriptで扱う型について記述していきます。
boolean
真偽値型ともいい、true
/false
の2つの値があります。条件式などでよく用いられます。
下のように宣言します。
今回はTypeScriptで最も重要となる「型の基礎」について説明していきたいと思います。ここでの「型」とは、データの性質のようなもので、どのように取り扱うべきかの定義だと考えてもらえばいいかと思います。
以下、TypeScriptで扱う型について記述していきます。
真偽値型ともいい、true
/false
の2つの値があります。条件式などでよく用いられます。
下のように宣言します。
let isChecked: boolean = true;
// - ①
let isDone: true = true;
// - ②
let isError: true = false;
// - ③コンパイルエラー
TypeScriptでは型を宣言する時に、:
を用いて、その右側に型を指定します。型を指定することを型アノテーション(type annotation)と呼びます。
①はboolean
型を明示的に伝えており、変数isChecked
にはtrue
/ false
の値を入れることができます。
②には値が特定のboolean
であること、今回はtrue
であることを明示的に伝えています。このように、特定のただ一つの値を表し、それ以外の値は受け入れない型のことをリテラル型(literal type)と呼びます。
そのため、③の例ではisError
はtrue
とTypeScriptに明示的に伝えたにも関わらずfalseを代入してしまっているのでコンパイルエラーが発生しています。
number
は整数、浮動小数点、Infinity、Nanなど、全ての数字の集合です。加減算や剰余など、数値に関する計算などをサポートします。
let num: number = 123;
// - ①
let fixedNum: 45.6 = 45.6;
// - ②
①の例は変数numがnumber
であることを宣言しています。
②の例では値が特定のnumber
であることを宣言しています。当然、異なる数値を代入するとコンパイルエラーが発生します。
bigint
はnumber
で扱えなかったより大きな整数を扱うことができます。具体的には、2^53以上の数値を扱うことができます。
let bigNum: bigint = 100n;
bigint
を宣言したら値の最後にn
をつけます。
string
は文字列を表します。以下のように宣言します
let message: string = "こんにちは";
let nightMessage: "こんばんは" = "こんばんは"
symbol
はES2015で導入された機能であり、オブジェクトなどで誤った値が設定されたくない時などに用いられます。シンボルはイミュータブル(不変)であり、コンストラクタを呼び出すことで宣言できます。
let key1: symbol = Symbol("hoge");
let key2: symbol = Symbol("hoge");
key1 === key2;
// false
let key3 = key1 + "fuga";
// エラー
symbol
は一意なので、他のどのsymbol
とも等しくなりません。
また、symbol
はイミュータブルなため値を変更することもできません。
TypeScriptにはobjectという型を用いてオブジェクトを表現することができます。
let obj: object = {
data: "hoge"
}
しかし、これだけではほとんど意味がなく、JavaScriptのオブジェクトであることしか宣言することができません。
オブジェクトの内部に型を指定する方法としては、以下のようにします。
let obj: (key: number) = {
key: 1
}
こうすることで、オブジェクトのkeyというプロパティにnumberの型を宣言することができました。これをオブジェクトリテラル表記と呼びます。
また、オブジェクトリテラル表記されたオブジェクトに型の異なるプロパティを追加したり、求められているプロパティを省略した例を見てみましょう。
let onamae: {
firstName: string
lastName: string
} = {
firstName: "Yoshio"
};
// エラー
onamae = {
nickName: "Yoshi"
};
// エラー
このように、予めオブジェクトに期待しているプロパティがなかったり、期待していないプロパティが代入されてしまうとTypeScriptはエラーを出します。
しかし、時にはプロパティを省略したり、追加したくなると思います。そんな時には以下のように記述します。
let address: {
country?: string,
[code: number]: string
};
address = {
1: "one"
};
// - ①
address = {
country: "America",
2: "two",
3: "third"
}
// - ②
address = {
country: "Japan"
}
// - ③
見慣れない表記が出てきたと思います。addressオブジェクトのcountryプロパティの右側に?
がついていますが、これは省略可能であることを示しています。具体的にはundifined
を受け入れることを表し、この場合はcountryプロパティはstring
とundifined
両方の型を受け入れます。
そのため、①の例のようにcountryプロパティが省略されてもエラーは出ません。
また、codeプロパティは[]
に囲まれていますが、この構文はインデックスシグネチャといい、オブジェクトが多くのプロパティを含む可能性を示します。インデックスシグネチャを使うことで、明示的に宣言したプロパティ以外にも多くのキーを安全にオブジェクトに追加することができます。
②のように、複数のnumber
の型を持つプロパティとstring
の型を持つ値を与えることができます。
さらに、③の例のように省略することも可能です。
ただし、インデックスシグネチャには注意点があり、プロパティの型はnumber
かstring
しか使えないということです。
TypeScriptで配列に型をつける場合は以下のよう型アノテーションの後に[]
をつけます。
let stringArray: string[];
stringArray = ["hoge", "fuga"];
タプルは配列の派生であり、配列の長さを固定することができます。以下に例を示します。
let numStringTuple: [number, number, string] = [1, 2, "3"];
let optionalTuple: [number, number?] = [1];
let variableTuple: [string, ...string[]] = ["A", "B", "C", "D"];
タプルは配列宣言と似ており、違いは[]
内に型を記述することです。タプル内で?
表記を使うことで省略可能な要素を記述することもできますし、最後の例のように可変長の要素も使えます。
any
はなんでも代入可能な型です。最終手段の型であり、TypeScriptの恩恵を全く受けれなくなる(型安全性を保証できなくなる)ので、極力使わないほうがいいでしょう。
let allOK: any;
allOK = "ok?"
allOK = 123;
allOK = true;
// 全て許容される
unknown
はany
と同様、型がわからない時に使う場合がありますが、こちらを優先して使ってください。なぜならunknownは与えられた値の型を絞り込むまで値を使用させないようにしてくれるからです。例を見てみましょう。
let unknownValue: unknown = 100;
let u = unknownValue + 1;
// コンパイルエラー: Object is of type 'unknown'
if (typeof unknownValue === "number") {
let num = unknownValue + 100;
}
// unknownValueがnumberであることが保証されたため使用することができる!
変数unknownValue はunknown
型を与えらたので、その型がわからないまま使用する(この例では1を足す)と、エラーとなってしまいます。
しかし、型をnumberに絞り込んであげることで型が保証され、その値を使用することができることができます。これらからanyよりも型安全性が高く、こちらを使うことを推奨します。
JavaScriptには値がないことをnull
, undefined
を用いて表します。null
は値が入っていないことを意味し、undefined
はまだ定義がされていないことを意味します。TypeScriptではこれらを型として扱うことができます。
let n: null;
let u: undefined;
さらにTypeScriptには値がないことを識別するためにvoid
, never
の2つの型を用意しています。void
は明示的に何にも返さない関数の戻り値の型であり、never
は決して返ることのない(例外をスローする場合や、無限ループなど)関数の型です。
function logger() : void {
console.log("何も返さないよ");
}
function errorGenerator() :never{
throw TypeError("決して返らないよ");
}
このようにTypeScriptでは他の静的型付け言語で扱えるような型やそれ以上にさまざまな型を宣言できることがわかっていただけたと思います。
次回はこれらの型をさらに柔軟に利用する方法について説明していきます!
それでは🙌
参考: https://www.typescriptlang.org/docs/handbook/basic-types.html