Пейджер

🌍 Привет мир! 👋🏻

🌍 Привет мир! 👋🏻

На днях узнал о существовании интересной фичи в TypeScript, которая была введена в TypeScript 5.0, const в параметрах типов.

🚀 Мотивация

До TypeScript 5.0 по классике, если передавался массив или объект в качестве аргумента функции, то в результате он становился обобщенным (упрощался до более общего типа).

📝 Например:

function getFirst<T>(arr: T[]): T {
  return arr[0];
}

const result = getFirst(["hello", "world"]); // string


‼️ Но иногда для дальнейшего взаимодействия с данными на выходе функции, необходимо сохранить конкретные литеральные значения.

📝 Например:

const result = getFirst(["hello", "world"]); // "hello" | "world"


Ранее для достижения необходимого результата приходилось использовать as const или satisfies.

Как использовать const type parameters

Очень важно понимать, что на вход функции необходимо передавать только точные типы, что это означает?

👎🏻 Плохо

const helloWorld = ["hello", "world"]; // string[]
const result = getFirst(helloWorld);


В данном случае, typescript уже распознал тип как string[], и поэтому даже если используется const type parameters в функкции, то ts не сможет из обобщенного типа string[] сделать вам точный ["hello", "world"]

👍🏻 Хорошо

const result = getFirst(["hello", "world"]); // "hello" | "world"
// или 
const helloWorld = ["hello", "world"] as const;
const result = getFirst(helloWorld);


Рабочий пример с использованием const type parameters и сохранением точных типов:

function createConfig<
const T extends Record<string, { mode: string; port: number }>>(config: T): T {
  return config;
}

const serverConfig = createConfig({
  dev: { mode: "development", port: 3000 },
  prod: { mode: "production", port: 8000 },
});


В данном случае в результате мы получаем тип:

const serverConfig: {
    readonly dev: {
        readonly mode: "development";
        readonly port: 3000;
    };
    readonly prod: {
        readonly mode: "production";
        readonly port: 8000;
    };
}


Без использования const type

const serverConfig: {
    dev: {
        mode: string;
        port: number;
    };
    prod: {
        mode: string;
        port: number;
    };
}


🧐 Думаю можно не объяснять, польза очевидна.

Как итог можно избегать использование as const везде, где нужно сохранять точное значение.

Когда полезно использовать

📌 При необходимости улучшить точность, когда работаете с литеральными массивами или объектами, так как TypeScript по умолчанию склонен обобщать (widen) массивы и объекты, приводя их к менее точным (более общим) типам.
📌 При создании гибких, но точных API, конфигурации объектов или маппинга.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#TYPESCRIPT
Медиа 1
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @ivanchikovitclub Открыть пост в Telegram