本文へスキップ
Typle
ログイン状態を確認中

プログラミング · 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を検証したことにはならない)

ほかの公式パックを見る