Вопрос или проблема
Я пытаюсь ограничить аргумент функции только объединяющим типом.
Например:
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[]>
. Многочисленные попытки, которые могли не иметь смысла, поэтому не делюсь здесь, но мне интересно, есть ли способ сделать это возможным.
Просто повысите уровень универсального типа:
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 ^^
Ответ или решение
В 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"); // Эта строка вызовет ошибку!
Объяснение кода:
-
Определение типа: Определяем
UnionType
какreadonly string[]
. Это позволяет создать массив строковых значений, которые не могут быть изменены. -
Параметры типа: Используем
<const T extends UnionType>
для ограничения параметраarg
только на массивы, которые могут быть помечены какconst
. Это позволяет сохранять типизацию и исключает возможность передачи массивов, не помеченных какconst
. -
Автозавершение: Внутренняя функция, возвращаемая
getSelector
, может принимать элементы типаT[number]
, что означает, что она автоматически извлекает возможные значения из переданного массива. -
Ошибки компиляции: Попытка передать недопустимый элемент, например, "optD", приводит к ошибке компиляции. Это и есть желаемое поведение — функция будет принимать только заранее определенные константные значения.
Эта реализация эффективна для ограничения аргументов функции так, чтобы они полностью соответствовали комбинированному типу, обеспечивая безопасность типов и комфортность работы с автозавершением. Убедитесь, что вы используете TypeScript 5.0 или более поздние версии, чтобы воспользоваться всеми преимуществами этой функции.