【第12回】指示の代わりに型で伝える|基本の型注釈(嫁子が教えるTS講座)
今回のゴール
: stringのような型注釈をひととおり読める- 書かなくていい場所(型推論)が分かる
anyを見つけたら立ち止まれるようになる
前回(なぜ型が要るのか)で動機の話は済みました。今回は書き方です。全体の流れは講座の目次へ。
嫁子: 今日は覚えることが多く見えるけど、実際に自分で書く量はそんなに多くないよ。
TypeScriptって、賢いところがあってね。書かなくても分かるものは勝手に判断してくれるの。だから「全部の変数に型を書く」みたいな話にはならない。
それより大事なのは、AIが書いた型注釈を読んで、意図が合ってるか判断できることだね。今日はそっち側で読んでいこう。
① 変数につける
変数名: 型 の順で書きます。
const name: string = "牛乳";
const price: number = 250;
const done: boolean = false;
第4回でやった3つがそのまま型の名前になります。ただし上の3行は、全部書かなくて構いません。理由は次で説明します。
② 書かなくていい場所(型推論)
TypeScriptは、代入されたものを見て型を判断します。
const price = 250; // number だと分かる
const name = "牛乳"; // string だと分かる
price.toUpperCase();
// エラー: プロパティ 'toUpperCase' は型 'number' に存在しません
型を1文字も書いていないのに、間違いはちゃんと指摘されます。これが型推論です。
| 書く場所 | 判断 |
|---|---|
| 変数(初期値あり) | 書かなくていい |
| 関数の引数 | 必ず書く(推論できない) |
| 関数の戻り値 | 書かなくてもいいが、書くと意図がはっきりする |
| 空の配列から始めるとき | 書く(const items: Item[] = []) |
嫁子: 初心者向けの記事だと全部に型を書いてる例が多いんだけど、実務ではそこまで書かないよ。
判断の基準は単純で、推論に任せて困らないところは任せるの。かえって読みにくくなるからね。
③ 関数につける
引数と戻り値の2か所です。
function total(price: number, count: number): number {
return price * count;
}
最後の : number が戻り値の型です。何も返さない関数は void と書きます。
function render(): void {
console.log("描き直しました");
}
アロー関数でも位置は同じです。
const addTax = (price: number): number => price * 1.1;
戻り値の型を書いておくと、実装の間違いをその場で捕まえられます。「number を返すと宣言したのに文字列を返している」が、書いた瞬間にエラーになるからです。
嫁子: AIに書かせるときは、戻り値の型は書いてもらったほうがいいよ。
中身を書き間違えても、宣言と食い違った瞬間に止まるからね。宣言が、AI自身への検査になるの。
④ 配列とオブジェクト
配列は「中身の型 + []」です。
const names: string[] = ["牛乳", "卵"];
const prices: number[] = [250, 300];
オブジェクトは、形をそのまま書きます。
const item: { name: string; price: number } = {
name: "牛乳",
price: 250,
};
見ての通り長くなるので、実際は名前をつけて使い回します。その書き方が次回の type と interface です。
第5回でやった「オブジェクトの配列」は、組み合わせるとこうなります。
const items: { name: string; done: boolean }[] = [
{ name: "牛乳", done: false },
{ name: "卵", done: true },
];
⑤ 「無いかもしれない」を表す
現実には、値が無いこともあります。その場合は | で並べます。
let selected: string | null = null;
selected = "牛乳"; // これもOK
これはユニオン型といって、「どれか1つ」という意味です。文字列と数値のどちらでもいい、という書き方もできます。
let id: string | number;
オブジェクトの項目で「あってもなくてもいい」ものは ? をつけます。
type Item = {
name: string;
memo?: string; // 無くてもいい
};
? をつけた項目は、使う前に存在を確認しないとエラーになります。これが undefined の事故を防ぐ仕組みです。
if (item.memo) {
console.log(item.memo.length);
}
嫁子: この「使う前に確認しろ」が、最初はうるさく感じると思う。私も面倒だなと思ったよ。
でもこれ、第5回で見た
undefinedの事故を、全部前倒しで潰してるの。うるさいんじゃなくて、後で起きる分をここで払ってるんだね。
⑥ any — 使うと全部無効になる
型が分からないときに使える any というものがあります。
let data: any = getSomething();
data.whateverYouWant(); // 何を書いてもエラーにならない
any を書いた瞬間、その値についてはチェックが全部止まります。前回やった「実行前に止める」が効かなくなります。
AIは、型が面倒な場面で any を使って切り抜けることがあります。エラーは消えますが、問題は残ったままです。
| 見つけたら | どうするか |
|---|---|
any |
「any を使わずに型をつけて」と頼み直す |
unknown |
こちらは安全側。使う前に確認を強制される |
嫁子:
anyは「型チェックを止めてください」という宣言なの。だから見つけたら一度立ち止まってね。エラーが消えたから解決した、と思っちゃうところが危ないんだよ。消えたのはエラーであって、問題じゃないからね。
つまずきポイント
: は型、= は値です。const price: number = 250 は「price は数値型で、値は250」と読みます。
型の名前は小文字です。string であって String ではありません。大文字のほうも書けてしまいますが、別物なので使いません。
エラーメッセージは長いですが、最初の1行だけ読めば足ります。残りは詳細です。そのままAIに貼れば意味も教えてくれます。
今回のまとめ
- 型注釈は
変数名: 型の順。基本はstring/number/boolean - 変数は推論に任せてよい。関数の引数は必ず書く
- 配列は
string[]、戻り値なしはvoid - 「無いかもしれない」は
string | nullやmemo?: stringで表す anyはチェックを止める宣言。AIが使っていたら直させる
次にやること
次回はinterface と typeです。今日長々と書いた { name: string; done: boolean } に名前をつけて、使い回せるようにします。
今回の宿題:第10回で作った買い物メモの items に、型をつけるとしたらどう書くか考えてみてください。答えは次回に出てきます。
嫁子: 考えるだけでいいよ。手が動かなくても、「name は文字列で、done は真偽値だな」と頭の中で言えたら十分だから。
それがそのまま次回の内容になるからね。