0Pricing
TypeScript Academy · レッスン

ジェネリックinterfaceとtype alias

ジェネリックなinterfaceとtype aliasを定義し、制約やデフォルトを追加して、それぞれの得意な場面を理解します

「ジェネリックinterfaceとtype alias」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン1/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全3レッスンが含まれています。

導入

目標:ジェネリックインターフェースと型エイリアスを使って、再利用可能な形を作成します。制約やデフォルトを追加し、両者の主な違いを学びます。

レッスンの概要

目標:coroutineScopeによる構造化並行性を適用し、例外の伝播を理解して、キャンセルのツールを安全に使用します。

主な考え方

  • coroutineScopeはすべての子を待機し、失敗すると兄弟コルーチンをキャンセルします。
  • launchはスコープ内ですぐに失敗し、asyncはawait()でエラーを表面化させます。
  • withTimeoutは制限時間を超えると処理をキャンセルします。
  • try/catchでスコープをラップし、例外を処理します。

ジェネリックインターフェース

ジェネリックインターフェースは型パラメーターを保持します。呼び出し側で具体的な型に置き換えます(例:Box<number>)。

interface Box<T> {
  value: T;
}

const nBox: Box<number> = { value: 42 };
const sBox: Box<string> = { value: "ts" };
console.log(nBox.value, sBox.value);

ジェネリック型エイリアス

型エイリアスもジェネリックにでき、オブジェクト、関数、ユニオン、交差型を表現できます。

type Pair<A, B> = { first: A; second: B };

const p1: Pair<number, string> = { first: 1, second: "one" };
const p2: Pair<boolean, boolean> = { first: true, second: false };
console.log(p1, p2);

スコープの待機動作

coroutineScopeは、子コルーチンの処理がすべて完了した後にのみ完了する子スコープを作成します。

import kotlinx.coroutines.*

suspend fun doTwoTasks(): Unit = coroutineScope {
    // Both run concurrently and the scope waits for them
    launch { delay(150); println("Task A done") }
    launch { delay(100); println("Task B done") }
    // returning Unit implicitly after children complete
}

fun main() = runBlocking {
    doTwoTasks()
    println("Scope completed")
}

失敗による兄弟のキャンセル

1つの子コルーチンが例外をスローすると、スコープは兄弟コルーチンをキャンセルして呼び出し元に再スローします。呼び出し箇所でtry/catchを使用します。

import kotlinx.coroutines.*

suspend fun failingGroup() = coroutineScope {
    val a = launch {
        try {
            repeat(5) { i ->
                println("A $i"); delay(60)
            }
        } finally {
            println("A cancelled")
        }
    }
    launch {
        delay(120)
        throw IllegalStateException("boom") // failure in child
    }
    a.join() // will be cancelled when sibling fails
}

fun main() = runBlocking {
    try {
        failingGroup()
    } catch (e: Exception) {
        println("Caught in caller: ${e.message}")
    }
    println("Caller continues")
}

制約

extends制約を追加すると、Tが必要なメンバー(例:id)をインターフェースのメソッドに公開するようにできます。

interface Repository<T extends { id: number }> {
  getById(id: number): T | undefined;
  save(entity: T): void;
}

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

const memRepo: Repository<User> = {
  store: [] as User[],
  getById(id) {
    return this.store.find(u => u.id === id);
  },
  save(u) {
    this.store.push(u);
  }
} as unknown as Repository<User>;

memRepo.save({ id: 1, name: "Ada" });
console.log(memRepo.getById(1));

async と await のエラー

asyncの例外はawait()を呼び出したときに発生します。try/catchで処理します。

import kotlinx.coroutines.*

suspend fun parseAsync(s: String) = coroutineScope {
    val deferred = async {
        delay(50)
        s.toInt() // may throw NumberFormatException
    }
    try {
        println("Result = ${deferred.await()}") // error appears here
    } catch (e: NumberFormatException) {
        println("Handled parse error: ${e::class.simpleName}")
    }
}

fun main() = runBlocking {
    parseAsync("12")
    parseAsync("xx")
}

デフォルトと拡張

使いやすさのためにデフォルト型パラメーターを指定し、ユーティリティ型を使って型を拡張します(例:Readonly<Box<T>>)。

interface ApiResponse<T = unknown> {
  data: T;
  ok: boolean;
}

type ReadonlyBox<T> = Readonly<Box<T>>;

const r1: ApiResponse = { data: "ok", ok: true };      // T defaults to unknown
const r2: ApiResponse<number> = { data: 200, ok: true };
const rb: ReadonlyBox<string> = { value: "fixed" };
// rb.value = "change"; // Error: readonly

withTimeout によるキャンセル

withTimeoutを使用して処理に制限時間を設けます。子コルーチンをキャンセルし、TimeoutCancellationExceptionをスローします。

import kotlinx.coroutines.*

suspend fun slowOp(): Int {
    delay(300) // pretend work
    return 42
}

fun main() = runBlocking {
    try {
        val result = withTimeout(150) { slowOp() } // cancels after 150ms
        println("Got $result")
    } catch (e: TimeoutCancellationException) {
        println("Timed out and cancelled")
    }
}

マージの違い

インターフェースは宣言マージをサポートします。型エイリアスはマージできず、同じ名前を重複して定義するとエラーになります。

interface Settings { theme: string }
interface Settings { lang: string }
// Merged: Settings has { theme: string; lang: string }
const s: Settings = { theme: "dark", lang: "en" };

// type Settings = { foo: string };
// Error: Duplicate identifier 'Settings' for type aliases (no merging)

構造化並行性における失敗のルール

coroutineScope では、1つの子コルーチンが例外で失敗すると何が起こりますか?

インターフェースと型の確認

クイックチェック:ジェネリックインターフェースと型エイリアスについて正しい説明はどれですか?

まとめ

まとめ:再利用可能な形を表現するには、ジェネリックインターフェースと型エイリアスを使います。制約とデフォルトを追加し、マージできるのはインターフェースだけであることを覚えておきましょう。

まとめ

まとめ:coroutineScopeで処理をまとめます。子コルーチンが失敗すると兄弟コルーチンをキャンセルします。エラーはtry/catchで処理し、asyncの失敗はawait()で表面化させ、長時間のタスクはwithTimeoutでキャンセルします。

よくある質問

「ジェネリックinterfaceとtype alias」レッスンは無料ですか?

はい。「ジェネリックinterfaceとtype alias」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全3レッスンが含まれています。

「ジェネリックinterfaceとtype alias」で何を学びますか?

ジェネリックなinterfaceとtype aliasを定義し、制約やデフォルトを追加して、それぞれの得意な場面を理解します ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

TypeScript Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/3です。

「ジェネリックinterfaceとtype alias」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このTypeScript Academyレッスンでコードを書いて実行できますか?

はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ジェネリックinterfaceとtype alias
  2. Conditional Types(入門)とunionへの分配
  3. データモデルの再利用可能なパターン
← TypeScript Academyに戻る