Есть ли способ ограничить аргумент только типом объединения?

Вопрос или проблема

Я пытаюсь ограничить аргумент функции только объединяющим типом.

Например:

type UnionType = readonly string[];

const getSelector = <T extends UnionType>(arg: T)=>{
  return (validType: T[number])=>{
    return 'данные ' + (!arg.includes(validType) ? "НЕ " : '') + "включены";
  }
}

const myFunc = getSelector(["opt1", "opt2", "opt3"] as const); // <== должно быть хорошо!
myFunc("opt1"); // автоподстановка работает!

const myFunc2 = getSelector(["optA", "optB", "optC"]);
myFunc2("optA"); // автоподстановка НЕ работает! поскольку заданные параметры не являются const.
// как я могу ОГРАНИЧИТЬ параметры как тип const?

Как видно из примера выше, я попытался создать расширенный тип с помощью ключевого слова readonly. Я также пробовал Readonly<string[]>. Многочисленные попытки, которые могли не иметь смысла, поэтому не делюсь здесь, но мне интересно, есть ли способ сделать это возможным.

Просто повысите уровень универсального типа:

Playground

const getSelector = <T extends string>(arg: T[])=>{
  return (validType: T) =>{
    return 'данные ' + (!arg.includes(validType) ? "НЕ " : '') + "включены";
  }
}

const myFunc = getSelector(['opt1', "opt2", "opt3"] as const); // <== должно быть хорошо!
myFunc('opt1'); // автоподстановка работает!

const myFunc2 = getSelector(["optA", "optB", "optC"]);
myFunc2('optA'); // автоподстановка НЕ работает! поскольку заданные параметры не являются const.
// как я могу ОГРАНИЧИТЬ параметры как тип const?

Это именно тот случай, для которого const параметры типов были выпущены в TypeScript 5.

Просто добавьте const к типу, и автоподстановка должна начать работать:

type UnionType = readonly string[];

const getSelector = <const T extends UnionType>(arg: T)=>{
  return (validType: T[number])=>{
    return 'данные ' + (!arg.includes(validType) ? "НЕ " : '') + "включены";
  }
}

const myFunc = getSelector(["opt1", "opt2", "opt3"] as const); // <== должно быть хорошо!
myFunc("opt1"); // автоподстановка работает!

const myFunc2 = getSelector(["optA", "optB", "optC"]);
myFunc2("optA"); // <== должно быть тоже хорошо!
// @ts-expect-error: Удалите эту строку, чтобы увидеть ошибку
myFunc2("optD"); // <== ОШИБКА!

^^ Похоже, что синтаксис сбивает с толку высокlighter SO ^^

Playground

Ответ или решение

В TypeScript вы можете ограничить аргументы функции так, чтобы они принимали только объединяемые типы, используя параметры типа с фиксированным массивом значений. Для этого достаточно воспользоваться возможностями, предоставленными в TypeScript 5.0, благодаря механизму const для параметров типа.

Ваш пример показывает, как реализовать эту логику. Вот как это можно сделать:

type UnionType = readonly string[];

const getSelector = <const T extends UnionType>(arg: T) => {
  return (validType: T[number]) => {
    return 'data is ' + (!arg.includes(validType) ? "NOT " : '') + "included";
  }
}

const myFunc = getSelector(["opt1", "opt2", "opt3"] as const); // Здесь всё работает!
myFunc("opt1"); // Автозавершение работает!

const myFunc2 = getSelector(["optA", "optB", "optC"]);
// Здесь также должно работать.
myFunc2("optA"); // Успешно компилируется!
// @ts-expect-error: Убедитесь, что тип не валиден
myFunc2("optD"); // Эта строка вызовет ошибку!

Объяснение кода:

  1. Определение типа: Определяем UnionType как readonly string[]. Это позволяет создать массив строковых значений, которые не могут быть изменены.

  2. Параметры типа: Используем <const T extends UnionType> для ограничения параметра arg только на массивы, которые могут быть помечены как const. Это позволяет сохранять типизацию и исключает возможность передачи массивов, не помеченных как const.

  3. Автозавершение: Внутренняя функция, возвращаемая getSelector, может принимать элементы типа T[number], что означает, что она автоматически извлекает возможные значения из переданного массива.

  4. Ошибки компиляции: Попытка передать недопустимый элемент, например, "optD", приводит к ошибке компиляции. Это и есть желаемое поведение — функция будет принимать только заранее определенные константные значения.

Эта реализация эффективна для ограничения аргументов функции так, чтобы они полностью соответствовали комбинированному типу, обеспечивая безопасность типов и комфортность работы с автозавершением. Убедитесь, что вы используете TypeScript 5.0 или более поздние версии, чтобы воспользоваться всеми преимуществами этой функции.

Оцените материал
Добавить комментарий

Капча загружается...