「プロパティに型を付ける」とは何をしているのか
オブジェクトは「名前付きの値の集まり」です。
TypeScriptでは、その「名前付きの値」1つ1つに対して、「ここにはこういう型の値だけ入ってほしい」というルールを付けられます。
これが「プロパティに型を付ける」ということです。
type User = {
name: string;
age: number;
};
TypeScriptこの2行で、TypeScriptに対してこう宣言しています。
「User という型のオブジェクトには、name という string のプロパティと、age という number のプロパティが必ずある」
ここから外れたオブジェクトを作ろうとすると、コンパイル時に止めてくれます。
基本構文:プロパティ名: 型
一番シンプルな形
type User = {
name: string;
age: number;
isAdmin: boolean;
};
TypeScriptname: string は「name プロパティには string を入れる」という意味です。age: number は「age には number」、isAdmin: boolean は「isAdmin には true/false」というルールです。
この型を使ってオブジェクトを作るとき、TypeScriptはそのルールを厳しくチェックします。
const u1: User = {
name: "Taro",
age: 20,
isAdmin: false,
}; // OK
const u2: User = {
name: "Hanako",
age: "20",
isAdmin: false,
// エラー: Type 'string' is not assignable to type 'number'.
};
TypeScript「プロパティに型を付ける」とは、
「この名前の箱には、この種類の値だけ入れていい」と決めることだとイメージすると分かりやすいです。
プロパティの型に使えるもの
プリミティブ型(string, number, boolean など)
一番よく使うのは、基本の型です。
type Product = {
id: number;
name: string;
price: number;
inStock: boolean;
};
TypeScriptここまでは直感通りだと思います。
「この項目は数字」「この項目は文字列」「この項目は真偽値」と、現実の意味とほぼ一致します。
オブジェクト型をプロパティに使う(入れ子構造)
プロパティの型として、別のオブジェクト型を使うこともできます。
type Address = {
city: string;
zip: string;
};
type User = {
name: string;
address: Address;
};
TypeScriptこうすると、
const u: User = {
name: "Taro",
address: {
city: "Tokyo",
zip: "100-0001",
},
};
TypeScriptというように、「中にさらに構造を持ったオブジェクト」を入れられます。
プロパティに型を付ける、というのは「構造をどこまで細かく表現するか」を決める作業でもあります。
配列型をプロパティに使う
type User = {
name: string;
tags: string[];
};
TypeScripttags: string[] は、「tags プロパティには string の配列が入る」という意味です。
const u: User = {
name: "Taro",
tags: ["admin", "paid"],
};
TypeScript「ここはリスト」「ここは1つの値」という違いも、プロパティの型で表現できます。
オプションプロパティ(?)と型の関係
「あってもなくてもいい」プロパティ
すべてのプロパティが必須とは限りません。
「あるかもしれないし、ないかもしれない」項目には ? を付けます。
type User = {
name: string;
age?: number;
};
TypeScriptこれは「age は number かもしれないし、そもそも存在しないかもしれない」という意味です。
const u1: User = { name: "Taro" }; // OK
const u2: User = { name: "Hanako", age: 18 }; // OK
TypeScript使う側では、「ないかもしれない」ことを意識して書く必要があります。
function printUser(user: User) {
console.log(user.name);
if (user.age !== undefined) {
console.log(user.age);
}
}
TypeScript? を付けるかどうかは、
「この項目は本当に必須か?」
という設計の話です。
「なんとなく全部オプション」にしてしまうと、逆に型の意味が弱くなります。
プロパティに型を付けることで防げるミス
1つの項目に違う型を入れてしまうミス
type User = {
name: string;
age: number;
};
const u: User = {
name: "Taro",
age: "20", // 本当は number にしたかったのに…
};
TypeScriptJavaScriptならこのまま通ってしまいますが、TypeScriptはここで止めてくれます。
「age は number だと約束したよね?」と。
プロパティ名の打ち間違い
type User = {
name: string;
age: number;
};
const u: User = {
name: "Taro",
agge: 20,
// Object literal may only specify known properties...
};
TypeScriptagge のようなタイプミスも、「そんなプロパティは User にない」と教えてくれます。
プロパティに型を付けることは、「名前のスペル」まで含めて仕様にしてしまう、ということでもあります。
初心者がまず掴んでおきたい「プロパティに型を付ける」感覚
プロパティに型を付ける、というのは単に「型注釈を書く作業」ではありません。
本質的には、こういうことをやっています。
「このオブジェクトは、こういう項目を持っているべきだ」
「この項目には、こういう種類の値だけ入っていてほしい」
「この項目は必須、この項目はあってもなくてもいい」
つまり、「データの形とルールを、自然言語ではなく型として書き下す」作業です。
ユーザー情報、商品情報、設定、レスポンスのJSON…
そういう「意味のあるまとまり」を見つけたら、
一度 { プロパティ名: 型 } の形で書き出してみる。
そこから、「型が設計を支えてくれる」感覚が、かなりはっきり見えてきます。
