スポンサーリンク

any卒業!TypeScript型練習プロンプト集(実務ケース別)

スポンサーリンク
この記事は約21分で読めます。
スポンサーリンク

「型エラー、正直こわいです…」
「エラー文、何言ってるか全然わからないです…」
「もういいや、とりあえず any で通します…」

こんな気持ち、ありませんか?

TypeScriptを書いているのに、型がストレスになっている人はめちゃくちゃ多いです。でも安心してください。型は“才能”ではなく、練習の型(やり方)を知ればちゃんと書けるようになります。

この記事では、実務でよくあるケースをもとにした「プロンプト形式の練習問題」を用意しています。
初級(型の形に慣れる)→ 中級(unionと型ガード)→ 実務レベル(ジェネリクス)という順番で進めば、any に逃げなくても戦えるようになります。

ただし注意です。
コピペして満足、はNGです。
まず自分で考える → そのあと改善例を見る この順番でいきましょう。

筆者
筆者

今日から一緒に、any 卒業していきましょう。

  1. TypeScriptの「型がつらい」あるあると最短の進め方
    1. まずはここだけ:型で守りたい3つ
    2. anyが増える本当の理由(悪者じゃないが危険)
    3. この記事の使い方:プロンプト→答え→振り返り
  2. 3分で整理!interface / type の使い分け
    1. 結論:迷ったらこう決める(早見表)
    2. 実務でよくある「型の作り方」パターン
    3. よくあるミス:差分が出る場面(拡張・合成)
  3. 初級プロンプト:まずは「型の形」に慣れる
    1. 🧭 型を作るミニ手順(毎回これ!)
    2. プロンプト① APIレスポンスの基本型(配列・ネスト)
    3. プロンプト② フォーム入力の型(必須/任意、null)
    4. プロンプト③ union型の基本(状態を表す型)
    5. プロンプト④ anyを使うと壊れる例
  4. 中級プロンプト:union × 型ガードで実務っぽくする
    1. 型ガードの型(in / typeof / instanceof)
    2. APIの成功・失敗レスポンスを安全に分ける
    3. 「取りうる値」を狭める設計(literal型)
    4. エラー文の読み方テンプレ(どこを見る?)
    5. 🧠 エラー文テンプレ読み
  5. 実務レベル:ジェネリクスを「便利な道具」にする
    1. ジェネリクスは「型の引数」:まず1パターン覚える
    2. 共通関数(fetcher / mapper / cache)課題
    3. 制約(extends)とデフォルト型(=)の使いどころ
    4. 罠:Tを増やしすぎる/anyに戻る瞬間
  6. すぐ使える練習環境・教材と、any卒業チェックリスト
    1. 練習環境:Playground / ローカル最小構成
    2. 🌐 TypeScript Playground(無料・ブラウザ完結)
    3. 💻 ローカル最小構成(慣れてきたら)
    4. 実務で効く道具:lint・型検査・スキーマ検証
    5. 🛑 ESLint(TypeScript対応)
    6. 🤖 型チェックをCIで自動化
    7. 🧪 スキーマ検証(例:Zod)
  7. 付録:✅ any卒業チェックリスト(今日から使える)
  8. まとめ(次にやること3つ)
    1. ✅ 今日やること(10分でOK)
    2. ✅ 今週やること
    3. ✅ 来週やること
  9. よくある質問
スポンサーリンク

TypeScriptの「型がつらい」あるあると最短の進め方

「型がつらい…」と感じる理由、だいたい同じです。

  • エラー文が長くて読めない
  • 何から型を決めればいいかわからない
  • 急いでいて、とりあえず any を足してしまう

でも実は、守るポイントはたった3つだけでOKです。

まずはここだけ:型で守りたい3つ

型で守るのは、この3つだけ覚えてください。

  • 入力(受け取るもの)
    • 関数の引数、フォーム入力、APIのリクエストなど
  • 出力(返すもの)
    • 関数の戻り値、APIレスポンス
  • 分岐(場合分け)
    • 成功か失敗か、ログイン済みか未ログインか、など

この3つを守るだけで、「どこから手をつけるの?」問題はかなり減ります。


anyが増える本当の理由(悪者じゃないが危険)

any が増えるのは、サボりではありません。

  • データの形がまだわからない
  • 型エラーが怖い
  • 納期がヤバい

こんなときに、つい「とりあえず通す」ために使ってしまいます。

正直に言うと、any は悪者ではないです。
でも「全部OKです」と言ってしまうので、バグも一緒に通してしまうのが危険なんです。

例:
APIのレスポンスが { name: string } のはずなのに、
any にしていたせいで user.nmae とタイポしても気づけない、みたいなことが起きます。

守ってくれるはずの型が、いない状態になります。


この記事の使い方:プロンプト→答え→振り返り

この記事では、ただ説明するだけではありません。

毎回この流れでいきます。

  • お題を見る
  • まず自分で型を書く
  • NG例(any逃げ)を見る
  • 改善例を見る
  • 「なぜそうなるか」を確認する

この順番が超大事です。

「読むだけ」では型は強くなりません。
でも「1問でも自分で考える」と、一気に理解が進みます。

まずは、入力・出力・分岐の3つを守る

筆者
筆者

これだけ意識して、次の章から一緒に筋トレしていきましょう。

3分で整理!interface / type の使い分け

「interfaceとtype、結局どっち使えばいいんですか…?」

ここで毎回止まってしまう人、かなり多いです。
でも大丈夫です。今日は迷わない決め方を渡します。

まずは小学生でもわかる言い方でいきます。

  • interface=設計図(あとから足し算しやすい)
  • type=名札(組み合わせが自由)

これだけでだいぶスッキリします。


結論:迷ったらこう決める(早見表)

まずは決め打ちルールです。

やりたいこと使うのは?ひとこと理由
オブジェクトの形を作る(APIデータなど)interface後から拡張しやすい
型を組み合わせたい(A | B など)typeunionが得意
交差させたい(A & B)type合体が得意
既存の型を広げたいinterfaceextendsが自然
文字列の候補を限定したいtypeliteral型が書きやすい

迷ったらこうです。

  • オブジェクトの形 → interface
  • 組み合わせ系 → type

まずはこれでOKです。100点を目指さなくていいです。


実務でよくある「型の作り方」パターン

実務だと、こんな場面がよく出ます。

① APIレスポンス

interface User {
  id: number
  name: string
  email: string
}

→ データの「設計図」なのでinterfaceが自然です。


② ReactのProps

type ButtonProps = {
  label: string
  onClick: () => void
}

→ これはinterfaceでもOKです。
でも他の型と合体(&)する可能性があるならtypeが便利です。


③ 状態を表す型

type Status = "loading" | "success" | "error"

→ これはtype一択です。
interfaceでは書けません。


よくあるミス:差分が出る場面(拡張・合成)

ここがハマりどころです。

① interfaceは同じ名前だと“合体”する

interface User {
  name: string
}

interface User {
  age: number
}

→ これ、エラーにならずに合体します。

知らないと「なんで?」ってなります。


② typeは同名で作れない

type User = {
  name: string
}

type User = {
  age: number
}

→ これはエラーになります。


③ readonly や optional の付け忘れ

interface User {
  name: string
  age?: number
  readonly id: number
}

?readonly を忘れると、
「更新できないはずなのに更新できる」みたいな事故が起きます。


ここまでで大事なのはこれだけです。

  • 設計図っぽい → interface
  • 組み合わせ・限定 → type

まずは迷わず書くこと。
細かい違いは、使いながら覚えれば大丈夫です。

筆者
筆者

次は、実際に「型の形」をガンガン書いていきます。筋トレ開始です。

初級プロンプト:まずは「型の形」に慣れる

ここは型の筋トレゾーンです。
むずかしいことはやりません。

やることは毎回同じです。

🧭 型を作るミニ手順(毎回これ!)

  • キー(項目名)を全部見る
  • それぞれの型を決める(string?number?)
  • 任意かどうかを決める(? いる?)
  • ネストや配列があるかを見る

これを“機械みたいに”やるだけでOKです。


プロンプト① APIレスポンスの基本型(配列・ネスト)

1) 目的

APIの「配列+ネスト構造」を安全に書けるようになることです。

2) お題

ブログ記事一覧APIが次の形で返ってきます。

[
  {
    "id": 1,
    "title": "TypeScript入門",
    "author": {
      "name": "Taro",
      "email": "taro@example.com"
    }
  }
]

3) NG例(any逃げ)

const posts: any = fetchPosts()

→ これだと post.auther.name と打ち間違えても気づけません。

4) 改善例(型安全)

interface Author {
  name: string
  email: string
}

interface Post {
  id: number
  title: string
  author: Author
}

const posts: Post[] = fetchPosts()

5) コピペ用ChatGPTプロンプト

あなたはTypeScriptの先生です。
次のお題に対して、
(1)目的
(2)NG例(any使用)
(3)改善例(型安全)
(4)なぜそうするか
を順番に説明してください。

最後に、似た練習問題を1つ追加してください。

お題:ブログ記事一覧APIの型定義(配列+ネスト)

プロンプト② フォーム入力の型(必須/任意、null)

1) 目的

「必須」と「任意」をちゃんと分けられるようになることです。

2) お題

ユーザー登録フォーム:

  • name(必須)
  • email(必須)
  • age(任意)
  • bio(未入力ならnull)

3) NG例

type Form = any

→ 何が必須か全然わかりません。

4) 改善例

interface RegisterForm {
  name: string
  email: string
  age?: number
  bio: string | null
}

ここで大事なのは:

  • 入力しなくていい → ?
  • 入ってこない可能性 → null

違いを意識してください。

5) コピペ用ChatGPTプロンプト

あなたはTypeScriptの先生です。

次のお題に対して、
(1)目的
(2)NG例(any使用)
(3)改善例(型安全)
(4)なぜそうするか
を順番に説明してください。

最後に、似た練習問題を1つ追加してください。

お題:ユーザー登録フォームの型定義(必須/任意/nullあり)

プロンプト③ union型の基本(状態を表す型)

1) 目的

「どれか1つ」を型で表せるようになることです。

2) お題

画面の状態は次の3つだけです。

  • loading
  • success
  • error

3) NG例

let status: any = "loading"

"done" と書いても止まりません。

4) 改善例

type Status = "loading" | "success" | "error"

let status: Status = "loading"

これで "done" はエラーになります。
型がちゃんと守ってくれます。

5) コピペ用ChatGPTプロンプト

あなたはTypeScriptの先生です。

次のお題に対して、
(1)目的
(2)NG例(any使用)
(3)改善例(型安全)
(4)なぜそうするか
を順番に説明してください。

最後に、似た練習問題を1つ追加してください。

お題:画面状態を表すunion型

プロンプト④ anyを使うと壊れる例

1) 目的

「anyがなぜ危ないか」を体感することです。

2) お題

次の関数で、ユーザー名を表示します。

function printUser(user: any) {
  console.log(user.name.toUpperCase())
}

3) NGポイント

user = {} を渡してもコンパイルが通ります。
でも実行時にエラーになります。

4) 改善例

interface User {
  name: string
}

function printUser(user: User) {
  console.log(user.name.toUpperCase())
}

これで「nameがない」データは止められます。

5) コピペ用ChatGPTプロンプト

あなたはTypeScriptの先生です。

次のお題に対して、
(1)目的
(2)NG例(any使用)
(3)改善例(型安全)
(4)なぜそうするか
を順番に説明してください。

最後に、似た練習問題を1つ追加してください。

お題:anyを使った関数の危険性


ここまでできたら、
「型の形」はかなり慣れてきます。

筆者
筆者

次はもう一段レベルアップします。
union × 型ガードで、実務っぽくしていきます。

中級プロンプト:union × 型ガードで実務っぽくする

ここから一気に“現場感”が出ます。

ポイントはこれです。

unionは「どれか1つ」
型ガードで「これだ!」に絞る

この“絞る感覚”が身につけば、型エラーは怖くなくなります。


型ガードの型(in / typeof / instanceof)

まずは超基本の3つです。

  • typeof → 文字列?数字?などプリミティブ用
  • in → そのプロパティ持ってる?
  • instanceof → クラスのインスタンス?

例です。

type Result = 
  | { success: true; data: string }
  | { success: false; error: string }

function handle(result: Result) {
  if ("data" in result) {
    console.log(result.data)
  } else {
    console.log(result.error)
  }
}

Result は「どれか1つ」ですが、
"data" in result成功パターンに絞れます。

これが型ガードです。


APIの成功・失敗レスポンスを安全に分ける

1) 目的

成功と失敗を安全に分けられるようになることです。

2) お題

APIが次のどちらかを返します。

  • 成功:{ ok: true, data: User }
  • 失敗:{ ok: false, message: string }

3) NG例

type ApiResponse = any

response.data と書いても止まりません。
失敗時にクラッシュします。

4) 改善例

interface User {
  id: number
  name: string
}

type ApiResponse =
  | { ok: true; data: User }
  | { ok: false; message: string }

function handle(res: ApiResponse) {
  if (res.ok) {
    console.log(res.data.name)
  } else {
    console.log(res.message)
  }
}

res.ok を見るだけで、
TypeScriptが中身を自動で絞ってくれます。

これが「安全に分岐する」感覚です。


「取りうる値」を狭める設計(literal型)

たとえば権限。

type Role = "admin" | "editor" | "viewer"

これにすると、

let role: Role = "superuser" // ❌ エラー

勝手な値を止められます。

「文字列だけど自由ではない」
これがliteral型の強みです。


エラー文の読み方テンプレ(どこを見る?)

エラー文、怖いですよね。でも見る場所は固定です。

🧠 エラー文テンプレ読み

1行目:何がダメ?
→ 「Type ‘A’ is not assignable to type ‘B’」

次:どこで?
→ この変数?この引数?

最後:
→ 期待してる型(B)
→ 実際の型(A)

例:

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

訳すと:

「stringはnumberに入れられませんよ」

それだけです。
英語の長さにビビらなくて大丈夫です。


筆者
筆者

次はいよいよラスボスです。
ジェネリクスを“便利な道具”にしていきます。

実務レベル:ジェネリクスを「便利な道具」にする

ここ、いちばん苦手な人が多いところです。

「って何ですか…?」
「なんか急にむずかしいです…」

大丈夫です。覚えることは1つだけです。

共通化したいけど、型はちゃんと残したい
それがジェネリクスです。

ジェネリクスは「型の引数」:まず1パターン覚える

まずはこれだけ覚えてください。

function identity<T>(value: T): T {
  return value
}

意味はシンプルです。

  • T = 型の名前(あとで決まる)
  • 入れた型を、そのまま返す
identity<string>("hello")
identity<number>(123)

これで「型を保ったまま共通化」できます。

まずは
Tを1つだけで始めてください。
増やすのは必要になってからでOKです。


共通関数(fetcher / mapper / cache)課題

ここから実務っぽくいきます。


課題① fetcherを型安全にする

1) 目的

APIごとに違う型を、安全に受け取れるようにすることです。

2) NG例(any逃げ)
async function fetcher(url: string): Promise<any> {
  const res = await fetch(url)
  return res.json()
}

→ 何が返ってくるかわかりません。


3) 改善例(ジェネリクス使用)
async function fetcher<T>(url: string): Promise<T> {
  const res = await fetch(url)
  return res.json()
}

使う側:

interface User {
  id: number
  name: string
}

const user = await fetcher<User>("/api/user")

これで user.name は安全に使えます。


課題② mapper関数

配列を変換する関数です。

NG例
function mapData(data: any[], fn: any) {
  return data.map(fn)
}

全部ゆるゆるです。


改善例
function mapData<T, U>(data: T[], fn: (item: T) => U): U[] {
  return data.map(fn)
}

ここで初めてTとUの2つを使いました。

でもルールは同じです。

  • 入力の型T
  • 変換後の型U

意味があるときだけ増やす
これがコツです。


制約(extends)とデフォルト型(=)の使いどころ

extendsは「安全ベルト」です。

例:

function getId<T extends { id: number }>(item: T) {
  return item.id
}

「idを持っている型だけ使えますよ」という制限です。

これを入れないと、

getId({ name: "Taro" }) // ❌

みたいな事故が起きます。


デフォルト型もあります。

function createArray<T = string>(value: T): T[] {
  return [value]
}

Tを指定しなければstringになります。

でも、最初は無理に使わなくて大丈夫です。


罠:Tを増やしすぎる/anyに戻る瞬間

よくある失敗です。

  • T, U, V, K, R, X…と増えすぎる
  • わからなくなって any に戻る

これは「設計が複雑すぎる」サインです。

対策はシンプルです。

  • まずT1つで考える
  • 本当に別の型が必要か考える
  • それでも無理なら関数を分ける

ジェネリクスは魔法ではありません。
共通化の道具です。



ここまで来たら、かなり強いです。

  • 共通化できる
  • 型を保てる
  • anyに戻らない
筆者
筆者

次は最後です。
環境を整えて、「any卒業」を固定化します。

すぐ使える練習環境・教材と、any卒業チェックリスト

ここまで読んで「なるほど…でも続くかな?」と思っていませんか?
大丈夫です。大事なのは環境を固定することです。

やる場所が決まっていれば、迷いません。


練習環境:Playground / ローカル最小構成

まずはこれでOKです。

🌐 TypeScript Playground(無料・ブラウザ完結)

  • インストール不要
  • エラーがすぐ出る
  • 設定も画面で変えられる

「1問だけ解く」には最強です。


💻 ローカル最小構成(慣れてきたら)

  • npm init -y
  • npm install typescript --save-dev
  • npx tsc --init

あとは .ts ファイルを作って書くだけです。

最初はフレームワーク不要です。
純粋な型練習だけで十分です。


実務で効く道具:lint・型検査・スキーマ検証

実務では「自分の意思」より「仕組み」が大事です。


🛑 ESLint(TypeScript対応)

  • any を使ったら警告
  • unsafeな代入を止める

「気合で守る」は無理です。ツールで止めましょう。


🤖 型チェックをCIで自動化

tsc --noEmit

PR時に型エラーを落とすだけで、
チームの安全度が一気に上がります。


🧪 スキーマ検証(例:Zod)

外から来るデータ(APIなど)は信用できません。

たとえば
Zod
のようなスキーマ検証ライブラリを使うと、

  • 入力データをチェック
  • 型も自動で推論

という「入り口で守る」設計ができます。

型は“出口”だけでなく、入口も守ると強いです。



付録:✅ any卒業チェックリスト(今日から使える)

anyを足す前に、これを順番に試してください。

  • unknown にして、使う場所でチェックできませんか?(型ガード)
  • 形が決まっているなら type / interface を作れませんか?
  • 「どれか」なら union(A | B)で表せませんか?
  • 取り出し方が共通なら ジェネリクス(<T>)にできませんか?
  • 外から来るデータは、入口で守りましたか?(スキーマ検証)
  • as を増やしていませんか?増えていたら型不足のサインです。
  • そのany、いつ消しますか?TODO期限を書きましたか?

型はセンスではありません。仕組みと反復です。

環境を決めて、
チェックリストを横に置いて、
1日1問でもいいので続けてください。

筆者
筆者

最後に、次にやることを3つにまとめます。

まとめ(次にやること3つ)

ここまで読んでくださったあなたは、もう「型が怖い人」ではありません。
あとは手を動かすだけです。

やることは、たった3つに絞りましょう。


✅ 今日やること(10分でOK)

初級プロンプトを2問だけ解いてください。
必ず「自分で書く → 改善例を見る」の順番です。

any を使いそうになったら、チェックリストを横に置きましょう。


✅ 今週やること

中級(union × 型ガード)を1テーマ通しでやってください。

  • 成功 / 失敗レスポンス
  • 状態管理
  • 権限のliteral型

「分岐を安全にする」感覚がつけば、一気に実務っぽくなります。


✅ 来週やること

ジェネリクス課題を1本だけちゃんとやりましょう。

  • fetcher
  • mapper
  • 共通関数

Tを1つから始めて、「共通化したいけど型は残したい?」を意識してください。


型はセンスではありません。反復と仕組みです。

any を減らすたびに、あなたのコードはちゃんと強くなっています。

筆者
筆者

今日から少しずつ、any卒業していきましょう。

よくある質問

Q
正直、anyってそんなにダメなんですか?
A

ダメというより、最後の手段です。

any は「全部OKです」と言ってしまう型なので、
タイポや想定外の値もスルーしてしまいます。

まずはチェックリストの順番で考えてください。

  • unknown にできませんか?
  • unionで表せませんか?
  • 型をちゃんと作れませんか?

どうしても今すぐ直せないときは、
// TODO: 型をあとで厳密にする と期限付きで残すのが現実的です。

Q
interfaceとtype、結局どっちに統一すればいいですか?
A

チームルールがあるならそれに従うのが最優先です。

個人なら、まずはこれでOKです。

  • オブジェクトの設計図 → interface
  • 組み合わせ(union・literal) → type

完璧な使い分けを目指すより、
迷って手が止まらない状態をなくすことが大事です。

Q
型エラーが英語で読めません…
A

見る場所は3つだけです。

  1. 何がダメ?(assignableって書いてある?)
  2. どこで?(この変数?引数?)
  3. 期待している型は?/実際の型は?

たとえば:

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

これは

stringはnumberに入れられませんよ

と言っているだけです。

長く見えるだけで、言ってることはシンプルです。

Q
ジェネリクス、毎回わからなくなります…
A

最初はこれだけでいいです。

function identity<T>(value: T): T

「入れた型を、そのまま返す」

これが理解できればOKです。

  • Tを1つだけ使う
  • 本当に必要なときだけ増やす

難しく感じたら、
「共通化したいけど型は残したい?」と自分に聞いてください。
YESならジェネリクスの出番です。

Q
実務で型を書く時間がありません…
A

めちゃくちゃわかります。

でも実は、型を書く時間は
バグ調査の時間を減らします。

  • APIの形がずれていた
  • nullチェックを忘れていた
  • 文字列の候補がバラバラだった

こういう事故を早めに止めてくれます。

全部を完璧にしなくていいです。

まずは

  • 入力
  • 出力
  • 分岐

この3つだけ守るところから始めてください。

それだけでも、any はかなり減ります。

タイトルとURLをコピーしました