TypeScriptBackend

TypeScript: предотвращаем путаницу идентификаторов с помощью брендированных типов

·MAGMA

Проблема смешивания идентификаторов

В типичном проекте на TypeScript мы часто сталкиваемся с ситуацией, когда разные сущности имеют одинаковые типы данных, например строки (string). Это может привести к ошибкам при передаче аргументов функций или методов, так как компилятор не видит разницы между такими значениями.

Например:

type UserId = string;
type OrderId = string;
async function getOrderDetails(userId: UserId, orderId: OrderId) {
    return db.orders.findFirst({
        where: { id: userId },
    });
}

Здесь легко случайно передать orderId, где ожидается userId. Компилятор не заметит ошибки, поскольку оба типа совпадают.

Что такое брендированные типы?

Брендированный тип позволяет добавить дополнительную информацию о типе на уровне системы типов TypeScript, не влияя на выполнение программы во время работы. Для этого используется пересечение примитивного типа и объекта с «призраковой» меткой (phantom type).

Пример реализации брендированного типа:

type Brand<T, B extends string> = T & { readonly _brand: B };
type UserId = Brand<string, 'UserId'>;
type OrderId = Brand<string, 'OrderId'>;

Теперь переменные этих типов нельзя использовать взаимозаменяемо, даже если они основаны на одном базовом типе (string):

const userId: UserId = "abc" as UserId;
const orderId: OrderId = "def" as OrderId;
getOrderDetails(userId, orderId);

Если попытаться поменять аргументы местами, компилятор выдаст ошибку.

Преимущества использования брендированных типов

Использование брендированных типов помогает избежать ошибок еще до запуска приложения, что улучшает качество кода и снижает вероятность появления багов в продакшен-среде. Кроме того, это решение не добавляет накладных расходов на этапе выполнения программы.

Вернуться к блогу
Предотвращаем ошибки идентификаторов в TypeScript — MAGMA