【TypeScript】型定義しない時あるのなんでなん?(初心者向け)

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)

投稿日: 2024年11月26日

学習振り返り
要約
  • TypeScriptではany型を避けることで型安全を保ち、意図しないエラーを防ぐことが重要である。
  • object型も同様に危険で、特定の型を定義することでより安全にプログラムを構築できる。
  • 型推論を活用し、必要に応じて明示的な型定義を行うことが推奨され、TypeScriptの効果を最大限に引き出すことができる。

はじめに

TypeScriptの章に入りたての頃、型を書いてる時と書いてない時があるけど、何が違ってそうなっているのかわからないと思いました。

私と同じ状況の方に向けて書いてみます。

原則

any型の値となるのを避ける

この方針で型付けしていますし、これでいいのではないかと思います。

ただ一部(思いつくのはobject型) anyにはならないけど避けた方がいい型はあります。

any型の危険なところ

なぜanyがダメかというと、anyにはどんな型の値でも入ってしまうので、TypeScriptの型安全であるというメリットがその値に関しては失われてしまうためです。

危険な例を見てみます。

const printLength = (array: any) => {
    console.log(array.length);
  };

printLength(10)

これ実行した時にエラー吐きますよね。

「lengthはありません~」みたいなエラーがコンソールに出力されるはずです。(試さなくてすみませんw)

printLengthの引数は配列であることを前提に処理しています。

でも関数に渡しているのは数値です。

any型にしているので型チェックされずエディターでエラーでません・・(怖い)

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

型定義しっかりすると、

const printLength = (array: number[]) => {
    console.log(array.length);
  };
  
  printLength(10)

エラー吐いてくれるのでオッと配列渡すんだった・・となるわけです。(心強い)

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

object型

const processInput = (input: object) => {
    //inputがどんなプロパティを持ってるかわからない
    console.log(input);
  };
processInput({});

オブジェクト型であれば中身が空でもエラーなく受け入れてしまいます。。(コワイ)

  type User = {
    id: number;
    name: string;
  };

  const processInput = (input: User) => {
    console.log(input);
  };
  processInput({});

こうするとprocessInputはUser型のオブジェクトしか受け付けないのでエラー吐いてくれて型安全が確保されます!

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

型推論

TypeScriptでは型を自動的に推論してくれるありがたい機能があります。

例えば、

let mystring = "文字列";

このmyStringという変数はstringと推論されます。

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

constで宣言すると再代入不可能な時点で"文字列“以外入りえない定数となるので文字列リテラル型と推論されます。

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

こういったときはわざわざ

let mystring:string = "文字列";

としなくてOKです。

言わなくても"文字列“入れてる時点でわかるからです。

他の例を見てみる

配列

const items = [];
items.push("文字列");
items.push(42);

この場合、itemsはany[]と推論されるので文字列でも数値でも受け入れます。

危険。。

const items: string[] = [];
items.push("文字列");
items.push(42);

この場合、

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

エラーになるので間違えて数値入れなくてよかった・・となりますね。

APIレスポンス

APIで受け取ったレスポンスに関してはどうでしょう。

const resp = await fetch("/api/posts/", { method: "GET" });
const data = await resp.json();

respの型はResponse型と推論されています。

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

その下のdataは・・?

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

anyです。

これはレスポンスがどんな型なのか確認して定義した方がいいです。

存在しないプロパティ(タイポ含む)にアクセスしようとしてundefindeになってたみたいなことも起きます。

【TypeScript】型定義しない時あるのなんでなん?(初心者向け)|ShiftBブログ

レスポンスにhogeというプロパティが存在しない場合もエラーにはならないのです。

コンソールに出力されるのはundefindeになると思います。

存在する前提でコード書き進めるとその先でエラー発生するというのがよくありそうです。

上手くいかない~と相談いただいて見ているとレスポンスの型定義していなくて、プロパティ名のタイポでというケース少なからずあります!

なんでもいけるんですよね・・(コワイ)

dataを使ったその後の処理の際にも型を定義しておくと全部定義した通りに補完機能が働くので絶対定義した方が便利です。

補完機能

補完機能については「え~っと、、このオブジェクトってどんなプロパティ持ってたっけ~」と見に行かなくても、data. で型情報をもとに存在するプロパティ候補を挙げてくれます。

これに慣れると絶対全部型定義した方が自分が楽になるしエラー減らせるから結果早いと実感して、TypeScriptなくてはならない存在になります。

まとめ

型定義しない時あるのなんでなん→型推論があるから!!です。

なにに定義したらいい? ?ってなったらanyがないように!と思って型つけてみてください!!!!!

定義してなくても推論されてたら明示的に定義しなくてOKです!!

ステートも無駄に型引数渡すことある気がします(ダメではないけど絶対必要ではない)

const [data, setData] = useState("");

初期値が空の文字列なのでdataはstringと推論されます。

const [data, setData] = useState<string>("");

こうしてもいいけどしなくてもいいって感じです。

初期値をnullにするときは型引数で<string|null>としましょう!!

const [data, setData] = useState<string|null>(null);

おわりに

TypeScriptって最初はわけわかんないのですが、身についてくるとないと不安な存在になります!!

そんな日が早く来る助けになればいいなと思います!!

シェア!

Threads
user
吉本茜
山口在住/二児の母/育休中
Loading...
記事一覧に戻る
Threads
0