ワイ「TypeScriptのエラーが読まれへん」


前回の記事の続きです。

TypeScriptが気に入ったワイ

ワイ「TypeScript、素敵やん」
ワイ「だって、ミスったコードを書くと・・・」

ワイ「↑こんな感じで、コンパイラが教えてくれるから」
ワイ「だいぶバグ発生率を抑えられそうや〜ん」

しかし

ワイ「おっ」
ワイ「またエラーメッセージが出たで」

ワイ「ファッ!?
ワイ「今度は英語やないか」
ワイ「しかもちょっと長い!」
ワイ「意味わからんで」
ワイ「Google翻訳してみよか」

タイプの引数 '{名前:文字列; 年齢:文字列; } 'はタイプ' User 'のパラメータに割り当てることはできません。
プロパティ「age」のタイプには互換性がありません。
タイプ 'string'はタイプ 'number'に割り当てることができません。

ワイ「いや翻訳しても分からん!」

助けを呼ぶ

ワイ「ハスケル子ちゃ〜ん!」

ハスケル子「なんですか」

ワイ「TypeScriptのエラーメッセージが読まれへんねん」

ハスケル子「(いや、それは知らん・・・)」
ハスケル子「(だって英語力の問題だから・・・)」
ハスケル子「とりあえず、何をしようとしたらエラーが出たんですか?」

ワイ「ええとやな・・・」

type User = {
  name: string
  age: number
}

ワイ「↑こんな感じのUserっていう型を定義したんや」

ハスケル子「なるほど」

  • ユーザーは、名前と年齢を持っている

ハスケル子「っていうことを表してるわけですね」
ハスケル子「いいじゃないですか」

ワイ「ほんで、実際にユーザ型の変数takashiを作ったんや」

const takashi = {
  name: 'たかし',
  age: '36'
}

ハスケル子「なるほど」

ワイ「そんで、次は関数を作って、実行しようとしたんや」
ワイ「引数としてUser型の値を受け取る関数や」

const makeProfileText = (user: User): string => {
  return `${user.name}${user.age}歳)`
}

ワイ「↑こんな感じでmakeProfileTextって関数を作ったんや」
ワイ「そんでこの関数に、takashiというユーザを渡して・・・」

const profileText = makeProfileText(takashi)

ワイ「↑こんな風に実行してやると・・・」

'たかし(37歳)'

ワイ「↑こんな感じの、プロフィール用のテキストを返してくれるっていう」
ワイ「そんな関数や」
ワイ「でも、ここでさっきの・・・」

ワイ「↑訳わからんエラーが出てもうたんや・・・」
ワイ「takashiいう変数が問題みたいや・・・」

ハスケル子「たぶん、一行ずつ読んでいけば分かりますよ」
ハスケル子「英語にビビらず、一行ずつ読んでいきましょう」

一行ずつ読んでいく

Argument of type '{ name: string; age: string; }' is not assignable to parameter of type 'User'.

ハスケル子「↑まずはここは・・・」

User型の引数として
{ name: string; age: string; }をぶち込むことはできまへん!

ハスケル子「↑こんな意味です」

ワイ「なるほどな」
ワイ「{ name: string; age: string; }ってのは何のこと?」

ハスケル子「それはtakashiという変数の型ですね」
ハスケル子「つまり」

User型の引数としてtakashiをぶち込むことはできまへん!

ハスケル子「↑ってことです」

ワイ「なるほどな」

ハスケル子「そして次の行は・・・」

Types of property 'age' are incompatible.

ageというプロパティの型が合ってまへんねん!

ハスケル子「↑ってことですね」
ハスケル子「そして最後の行は・・・」

Type 'string' is not assignable to type 'number'.

文字列型の値は、数値型にはぶち込めまへん!

ハスケル子「↑こうですね」
ハスケル子「まとめると・・・」

User型の引数としてtakashiをぶち込むことはできまへん!
ageというプロパティの型が合ってまへんねん!
文字列型の値は、数値型にはぶち込めまへん!

ワイ「なるほど」
ワイ「要約すると・・・」

takashiagestringだから、アカン!

ワイ「ってことか」

const takashi = {
  name: 'たかし',
  age: '36'
}

ワイ「あ、ほんまや」
ワイ「takashiage文字列になってしまってるわ」
ワイ「User型のagenumberのはずやのに」

ハスケル子「そういうことですね」
ハスケル子「一行ずつちゃんと読めば、意外と簡単ですよね」

ワイ「まあ、なんとかなりそうやな」

下の行から読んで行くのも吉

ハスケル子「具体的に修正すべきポイントは一番下の行に表示されているので」
ハスケル子「下から読むのも良いと思います」

文字列型の値は、数値型にはぶち込めまへん!
ageというプロパティの型が合ってまへんねん!
User型の引数としてtakashiをぶち込むことはできまへん!

ハスケル子「↑なんか読みやすくないですか?」

ワイ「ほんまや」

できるだけ型を書こう

ハスケル子「あと、takashiにも明示的に型を書いたほうが良いですよ」

ワイ「どういうこと?」

const takashi: User = {
  name: 'たかし',
  age: '36'
}

ハスケル子「↑こういうことです」
ハスケル子「こうしておくと・・・」

ワイ「おお、takashiageがアカンってことが一目瞭然やな」

ハスケル子「そうなんです」
ハスケル子「型情報を書かなくても、ある程度はTypeScriptくんが気を利かせてくれるんですが」

takashiUser型の値です!」
「私はそういうつもりでこのコードを書いてます!」

ハスケル子「っていう風に、能動的に型を書いて宣言したほうが」
ハスケル子「より正確なエラーメッセージを表示してもらえる可能性が高くなりますね」

ワイ「なるほどなぁ」

まとめ

Hoge型の引数としてfugaをぶち込むことはできまへん!
piyoというプロパティの型が合ってまへんねん!
aaa型の値は、bbb型にはぶち込めまへん!

  • TypeScriptでは↑この形式のエラーメッセージが表示されることが多い。
  • 英語だし文が長めだし、怯みそうになるけど、一行ずつ読めば意外と何とかなる。
  • 下の行から読んで行くと、直すポイントが分かりやすいかも。
  • 型は能動的に書いていこう。そのほうがエラーの意味が分かりやすくなるよ。

ワイ「↑ってことやな!」

ハスケル子「ですね!」

〜おしまい〜