基本的な型について

Posted: 2020/8/1
TypeScript/
基本の型

今回は TypeScript で最も重要となる「型の基礎」について説明していきたいと思います。ここでの「型」とは、データの性質のようなもので、どのように取り扱うべきかの定義だと考えてもらえばいいかと思います。

以下、TypeScript で扱う型について記述していきます。

boolean

真偽値型ともいい、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)**と呼びます。

そのため、③ の例ではisErrortrueと TypeScript に明示的に伝えたにも関わらず false を代入してしまっているのでコンパイルエラーが発生しています。

number

numberは整数、浮動小数点、Infinity、Nan など、全ての数字の集合です。加減算や剰余など、数値に関する計算などをサポートします。

let num: number = 123;
// - ①
let fixedNum: 45.6 = 45.6;
// - ②

① の例は変数 num がnumberであることを宣言しています。

② の例では値が特定のnumberであることを宣言しています。当然、異なる数値を代入するとコンパイルエラーが発生します。

bigint

bigintnumberで扱えなかったより大きな整数を扱うことができます。具体的には、2^53 以上の数値を扱うことができます。

let bigNum: bigint = 100n;

bigintを宣言したら値の最後にnをつけます。

string

stringは文字列を表します。以下のように宣言します

let message: string = "こんにちは";
let nightMessage: "こんばんは" = "こんばんは";

symbol

symbolは ES2015 で導入された機能であり、オブジェクトなどで誤った値が設定されたくない時などに用いられます。シンボルはイミュータブル(不変)であり、コンストラクタを呼び出すことで宣言できます。

let key1: symbol = Symbol("hoge");
let key2: symbol = Symbol("hoge");

key1 === key2;
// false
let key3 = key1 + "fuga";
// エラー

symbolは一意なので、他のどのsymbolとも等しくなりません。

また、symbolはイミュータブルなため値を変更することもできません。

object

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 プロパティはstringundifined両方の型を受け入れます。

そのため、① の例のように country プロパティが省略されてもエラーは出ません。

また、code プロパティは[] に囲まれていますが、この構文はインデックスシグネチャといい、オブジェクトが多くのプロパティを含む可能性を示します。インデックスシグネチャを使うことで、明示的に宣言したプロパティ以外にも多くのキーを安全にオブジェクトに追加することができます。

② のように、複数のnumberの型を持つプロパティとstringの型を持つ値を与えることができます。

さらに、③ の例のように省略することも可能です。

ただし、インデックスシグネチャには注意点があり、プロパティの型はnumberstringしか使えないということです。

配列

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

anyはなんでも代入可能な型です。最終手段の型であり、TypeScript の恩恵を全く受けれなくなる(型安全性を保証できなくなる)ので、極力使わないほうがいいでしょう。

let allOK: any;
allOK = "ok?";
allOK = 123;
allOK = true;
// 全て許容される

unknown

unknownanyと同様、型がわからない時に使う場合がありますが、こちらを優先して使ってください。なぜなら 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 よりも型安全性が高く、こちらを使うことを推奨します。

null, undefined

JavaScript には値がないことをnull, undefinedを用いて表します。nullは値が入っていないことを意味し、undefinedはまだ定義がされていないことを意味します。TypeScript ではこれらを型として扱うことができます。

let n: null;
let u: undefined;

void, never

さらに 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