Версия T extends string
, кажется, работает хорошо.Он запрещает impossible
, но разве вы не хотели бы запретить его, поскольку, если параметр никогда не может иметь этого значения, эта опция была бы бесполезна?:
export const mySwitch = <T extends string>(value: T, possibilities: {[key in T]: any}): any => {
return possibilities[value];
};
declare let option: "val1" | "val2" | "val3";
mySwitch(option, {val1: "s1", val2: "s2", val3: "s3", impossible: "impossible"});
play
Если вы хотите разрешить дополнительные ключи, вы можете объявить объект case отдельно (минуя проверки лишних свойств и повторно использовать объект case)
declare let option: "val1" | "val2" | "val3";
const casses = {val1: "s1", val2: "s2", val3: "s3", impossible: "impossible"}
mySwitch(option, casses);
play
Или вы можете немного изменить свой тип, чтобы универсальный параметр типа был объектом case, и значение будет набрано как keyof T
:
export const mySwitch = <T>(value: keyof T, possibilities: T): any => {
return possibilities[value];
};
declare let option: "val1" | "val2" | "val3";
mySwitch(option, {val1: "s1", val2: "s2", val3: "s3", impossible: "impossible"});
play
Также лучшим вариантом будет сохранение типа из объекта case вместо использования any
:
export const mySwitch = <T, K extends keyof T>(value: K, possibilities: T): T[K] => {
return possibilities[value];
};
declare let option: "val1" | "val2" | "val3";
mySwitch(option, {val1: 1, val2: "s2", val3: "s3", impossible: false}); // returns string | number
play
Редактировать:
Чтобы сохранить как правильный тип возврата, так и ошибку, если есть возможности, отсутствующие в объединении, вы можете использовать это:
const mySwitch = <T extends Record<K, any>, K extends string>(value: K, possibilities: T & Record<Exclude<keyof T, K>, never>): any => {
return possibilities[value];
};
let option: "val1" | "val2" | "val3" = (["val1", "val2", "val3"] as const)[Math.round(Math.random() * 2)]
mySwitch(option, {val1: "s1", val2: "s2", val3: "s3" });
mySwitch(option, {val1: "s1", val2: "s2", val3: "s3", impossible: "" }); //err on impossible
play
Обратите внимание, что, поскольку машинописный текст управляет анализом потока, вы должны убедиться, что option
iэто не просто типы как фактическая константа, которую вы назначаете вместо аннотации типа, которую вы указываете