プログラミング · TypeScript
TypeScript構文のタイピング練習
TypeScript の構文を、初級・中級・上級の3つのリストで打って覚えます。型注釈、ユニオン型、unknown と型の絞り込み、ジェネリクス、型エイリアスとインターフェースなどを、コードの形で練習できます。
3リスト・54語
無料・ログインなしで練習できます。押すとこのパックをフォローし、すぐに練習が始まります。
収録している言葉
TypeScript構文(初級)
| 打つ言葉 | 意味・補足 |
|---|---|
| // TypeScript 7.0 / strictを想定 | TypeScript 7.0:対象・構文と実装の区別(7.0は正式提供済み。大きな変更はネイティブ実装。下記は7で使う主要構文であり7で初登場の一覧ではない) |
| const name = 'Pomo'; let count = 0; count += 1; | const / let:再代入不可・可(constも参照先内部の変更は禁止しない) |
| const age: number = 20; const enabled = true; const text: string = 'Hello'; | 型注釈・推論:値の型(型は通常実行時に消える) |
| const name = 'Pomo'; const message = `Hello, ${name}`; | テンプレート文字列:値の埋込み(JavaScriptの実行時構文) |
| interface Named { name: string } interface User extends Named { id: number } | interface / extends:オブジェクト契約 |
| type User = { readonly id: number; name?: string }; | optional / readonly:任意・読取専用(readonlyは型検査上の制約。深い不変性ではない) |
| type Status = 'todo' | 'done'; let id: string | number = 1; | union / literal:候補の型 |
| const config = { mode: 'dark', sizes: [1, 2] } as const; | as const:リテラルを保持(型のreadonly化であり実行時Object.freezeではない) |
| function add(a: number, b: number): number { return a + b } | function / 戻り値型:関数定義 |
| const double = (n: number): number => n * 2; | arrow function:無名関数 |
| type User = { id: number; name: string }; type Name = User['name']; | T[K]:プロパティ型 |
| type Optional<T> = { [K in keyof T]?: T[K] }; | mapped types:キーを変換 |
| type Method = 'get' | 'post'; type EventName = `${Method}:users`; | template literal types:文字列型を組み立てる(実行時の文字列処理ではない) |
| class Counter { #count = 0; increment() { this.#count++ } } | #private / private:実行時・型上の非公開(TSのprivate修飾子とJSの#フィールドの保護レベルは異なる) |
| declare function externalApi(id: number): Promise<string>; | declare / .d.ts:実装が別にある型を宣言(実装は生成されない。実行時に別途必要) |
| npm install -D typescript@7.0 | ネイティブコンパイラー:型検査・ビルドの実装(公式7.0発表に基づく。速度改善はコードをGoで書き直すことを要求しない) |
| npx tsc --noEmit | ネイティブコンパイラー:型検査・ビルドの実装(公式7.0発表に基づく。速度改善はコードをGoで書き直すことを要求しない) |
| // TypeScriptを内部importするLint・変換・解析ツールの対応版を確認 | コンパイラーAPI互換性:周辺ツールの対応(7.0には従来のプログラム用コンパイラーAPIがない。必要な周辺ツールは公式の6系互換パッケージ等で併用。7.1のAPIとは区別) |
TypeScript構文(中級)
| 打つ言葉 | 意味・補足 |
|---|---|
| let name: string | null = null; const missing: undefined = undefined; const n: bigint = 1n; | null / undefined / bigint:基本型(bigint等はtarget・実行環境を確認) |
| function fail(message: string): never { throw new Error(message) } function log(): void { console.log('Hello') } | never / void:戻らない・有用な値なし(voidとundefinedの意味は完全には同じでない) |
| const user: { name?: string } | null = Math.random() > 0.5 ? {} : null; const name = user?.name ?? 'Guest'; | ?. / ??:null等への安全なアクセス(??はnull/undefinedだけ。||は0・空文字等にも反応) |
| type User = { id: number; name: string }; const user: User = { id: 1, name: 'Pomo' }; | type:型エイリアス(実行時に検証・生成するものではない) |
| type Named = { name: string }; type WithId = { id: number }; type User = Named & WithId; | intersection:型の組合せ(同名フィールドの矛盾で利用不能な型になり得る) |
| const routes = { home: '/', users: '/users' } as const satisfies Record<string, string>; | satisfies:型に適合することを検査(単純な型注釈より具体的な型情報を保てる) |
| const value: unknown = 'hello'; const text = value as string; /* nullableValue! は実行時チェックを追加しない */ | as / 非null !:型アサーション(外部入力に使っても安全性は保証されない) |
| type Transform = (value: number) => number; const twice: Transform = n => n * 2; | 関数型:関数を値にする |
| const age = 20; const label = age >= 20 ? '成人' : '未成年'; if (age >= 20) { console.log(label) } | if / switch / 三項:条件分岐(JavaScriptの構文) |
| for (const n of [1, 2, 3]) console.log(n); for (const key in { a: 1 }) console.log(key); | for of / for in:値・キーを反復(for inは継承された列挙可能プロパティも対象。配列要素には通常for of) |
| function size(value: string | number) { if (typeof value === 'string') return value.length; return value; } | typeof / in / instanceof:型の絞り込み |
| function identity<T>(value: T): T { return value } const n = identity(1); | <T>:型を抽象化 |
| function lengthOf<T extends { length: number }>(value: T) { return value.length } | extends制約:利用可能な操作を限定 |
| const user = { id: 1, name: 'Pomo' }; type User = typeof user; type UserKey = keyof User; | keyof / typeof:キー・値から型を作る(型位置のtypeofと実行時typeofを区別) |
| type ElementOf<T> = T extends readonly (infer U)[] ? U : T; type N = ElementOf<number[]>; | conditional types / infer:型の条件分岐・抽出(条件付き型のunionへの分配に注意) |
| type Scores = Record<string, number>; type S = 'a' | 'b'; type A = Exclude<S, 'b'>; type B = Extract<S, 'b'>; | Record / Exclude / Extract:辞書・unionの操作 |
| const values = await Promise.all([Promise.resolve(1), Promise.resolve(2)]); | Promise.all / allSettled:複数のPromise(top-level awaitにはESM等の設定が必要。allは最初のrejectで失敗扱い) |
| /* 正式7.0はtypescriptパッケージ。 */ /* @typescript/native-previewは正式版の導入例として使わない。 */ | 旧previewとの区別:導入パッケージ(7.1 Betaの新API・提案標準ライブラリ等を7.0の必須構文に混ぜない) |
TypeScript構文(上級)
| 打つ言葉 | 意味・補足 |
|---|---|
| const value: unknown = JSON.parse('{"id":1}'); if (typeof value === 'object' && value !== null) { console.log(value) } | unknown / any:未確定の型(unknownは絞り込みが必要。anyは型検査を回避するため乱用しない) |
| const nums: number[] = [1, 2]; const pair: [string, number] = ['Pomo', 20]; const fixed: readonly number[] = [1, 2]; | Array / tuple / ReadonlyArray:配列・固定構造(通常の配列アクセスでundefinedを扱うにはnoUncheckedIndexedAccess等) |
| function greet(name = 'Guest', suffix?: string) { return name + (suffix ?? '') } function sum(...nums: number[]) { return nums.reduce((a, b) => a + b, 0) } | 既定・任意・rest:引数の柔軟な指定(任意引数は通常undefinedを含む) |
| function label(value: string): string; function label(value: number): string; function label(value: string | number): string { return String(value) } | オーバーロード:複数の呼出シグネチャ(実装シグネチャがそのまま公開されるわけではない) |
| type User = { id: number }; function isUser(v: unknown): v is User { return typeof v === 'object' && v !== null && 'id' in v && typeof v.id === 'number'; } | ユーザー定義型ガード:unknownを検証(型述語の正しさは実装者が保証。抜けた検証を型が自動補完しない) |
| type Result = { ok: true; value: string } | { ok: false; error: string }; function show(r: Result) { return r.ok ? r.value : r.error } | 判別可能union:状態に応じて型を絞る |
| type State = 'todo' | 'done'; function label(s: State): string { switch (s) { case 'todo': return '未完'; case 'done': return '完了'; default: const neverValue: never = s; return neverValue; } } | neverで網羅確認:分岐漏れを検出(新たなState追加時に検出しやすい) |
| type User = { id: number; name?: string }; type Patch = Partial<User>; type Full = Required<User>; type Fixed = Readonly<User>; | Partial / Required / Readonly:プロパティ修飾(基本的に浅い型変換) |
| type User = { id: number; name: string; secret: string }; type PublicUser = Omit<User, 'secret'>; type IdOnly = Pick<User, 'id'>; | Pick / Omit:プロパティを選ぶ・除く(実データから値を除去する処理ではない) |
| function add(a: number, b: number) { return a + b } type R = ReturnType<typeof add>; type P = Parameters<typeof add>; type V = Awaited<Promise<number>>; | ReturnType / Parameters / Awaited:関数・Promiseから型を得る |
| class User { constructor(public readonly id: number, public name: string) {} greet() { return `Hello, ${this.name}` } } | class / constructor:クラスとプロパティ(TypeScriptのパラメータープロパティはJSへ変換が必要) |
| interface Greet { greet(): string } class Base { greet() { return 'Hello' } } class User extends Base implements Greet { override greet() { return super.greet() + '!' } } | extends / implements / override:継承・契約(implementsは実装を生成しない) |
| async function answer(): Promise<number> { return 42 } async function run() { const n = await answer(); console.log(n) } | async / await / Promise:非同期処理(Promiseの失敗・ライフサイクルを扱う) |
| try { throw new Error('失敗') } catch (e) { const message = e instanceof Error ? e.message : String(e); console.error(message); } | try catch / unknown:失敗処理(strict環境ではcatch値をunknownとして扱う) |
| export type User = { id: number }; export const answer = 42; /* 別ファイル: import type {User} from './user.js'; */ | export / import type:値と型の分離(拡張子・ESM/CJSはmoduleResolutionと実行環境に合わせる) |
| const user = { id: 1, name: 'Pomo' }; const { name } = user; const updated = { ...user, name: 'New' }; const doubled = [1, 2, 3].map(n => n * 2); | 分割代入 / spread / map:JSの基本データ操作(オブジェクトspreadは浅いコピー) |
| { "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "noUncheckedIndexedAccess": true, "noEmit": true } } | tsconfig strict / noEmit:型検査設定(Node向け例。フレームワーク・bundlerでは適切な設定へ変更) |
| const raw: unknown = JSON.parse('{"id":1}'); if (!isUser(raw)) throw new Error('invalid user'); console.log(raw.id); | satisfiesと実行時検証:外部データを扱う(isUserを定義。as・satisfies・型引数だけでJSONを検証したことにはならない) |