0Pricing
TypeScript Academy · Урок

Обобщённые интерфейсы и псевдонимы типов

Определяйте обобщённые интерфейсы и псевдонимы типов, добавляйте ограничения и значения по умолчанию, а также разбирайтесь, где каждый подход особенно полезен.

«Обобщённые интерфейсы и псевдонимы типов» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 1 из 3. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 3 уроков всего.

Введение

Цель: создавать повторно используемые формы с помощью обобщённых интерфейсов и псевдонимов типов. Вы добавите ограничения и значения по умолчанию, а также узнаете об основных различиях.

Обзор урока

Цель: применять структурированную конкурентность с помощью coroutineScope, понимать распространение исключений и безопасно использовать средства отмены.

Основные идеи

  • coroutineScope ожидает завершения всех дочерних задач; сбой отменяет соседние задачи.
  • Запуск завершается с ошибкой сразу в области видимости; асинхронная операция сообщает об ошибках при вызове await().
  • withTimeout отменяет работу после истечения заданного ограничения.
  • Оберните области видимости в конструкцию обработки исключений.

Обобщённый интерфейс

Обобщённый интерфейс содержит параметр типа. Вызывающий код подставляет конкретные типы (например, 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")
}

Сбой отменяет соседние задачи

Если одна дочерняя корутина выбрасывает исключение, область видимости отменяет соседние задачи и повторно выбрасывает исключение вызывающему коду; используйте обработку исключений в месте вызова.

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));

Ошибки асинхронных операций и await

Исключения асинхронных операций возникают при вызове await(); обрабатывайте их с помощью конструкции обработки исключений.

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 что происходит, если одна дочерняя корутина завершается с исключением?

Проверка интерфейсов и типов

Быстрая проверка: Какое утверждение об обобщённых интерфейсах и псевдонимах типов является TRUE?

Итоги

Итоги: Используйте обобщённые интерфейсы и псевдонимы типов для описания повторно используемых форм. Добавляйте ограничения и значения по умолчанию и помните: слияние поддерживают только интерфейсы.

Итоги

Итоги: используйте coroutineScope для группировки задач; сбой дочерней задачи отменяет соседние задачи. Обрабатывайте ошибки с помощью конструкции обработки исключений, получайте ошибки асинхронных операций при вызове await() и отменяйте длительные задачи с помощью withTimeout.

Часто задаваемые вопросы

Урок «Обобщённые интерфейсы и псевдонимы типов» бесплатный?

Да — полный текст урока «Обобщённые интерфейсы и псевдонимы типов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 3 уроков всего.

Чему я научусь в уроке «Обобщённые интерфейсы и псевдонимы типов»?

Определяйте обобщённые интерфейсы и псевдонимы типов, добавляйте ограничения и значения по умолчанию, а также разбирайтесь, где каждый подход особенно полезен. Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать TypeScript Academy?

Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 3.

Сколько времени занимает урок «Обобщённые интерфейсы и псевдонимы типов»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке TypeScript Academy?

Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Обобщённые интерфейсы и псевдонимы типов
  2. Условные типы (введение) и распределение по объединениям
  3. Повторно используемые шаблоны для моделей данных
← Назад к TypeScript Academy