繁体   English   中英

Typescript 通用联合类型

[英]Typescript generic union type

我正在尝试创建一个简单的开关 function ,它采用第一个参数,该参数必须是字符串和 object 的联合,它具有基于第一个参数联合的键并且可以返回任何值。

export const mySwitch = <T extends string>(value: T, possibilities: {[key in T]: any}): any => {
    return possibilities[value];
};

典型用法是

let option: "val1" | "val2" | "val3" = "val1";
// should returns s1
// Impossible should be type-checked as an error since it's not part of the option union type
mySwitch(option, {val1: "s1", val2: "s2", val3: "s3", impossible: "impossible"});

出现我的问题是因为泛型类型T必须是string才能用作 object 键。 我不知道你怎么能告诉Tstring的并集。

我试过T extends string没有成功。

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"}); 

如果您想允许额外的键,您可以单独声明案例 object (绕过多余的属性检查并允许您重用案例对象)


declare let option: "val1" | "val2" | "val3";
const casses = {val1: "s1", val2: "s2", val3: "s3", impossible: "impossible"}
mySwitch(option, casses); 

或者你可以稍微改变你的类型,这样泛型类型参数就是 object,值将被键入为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"}); 

另外一个更好的选择是保留案例 object 的类型,而不是使用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

编辑:

如果联合中不存在可能性,要保留正确的返回类型和错误,您可以使用以下命令:

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

请注意,因为 typescript 进行控制流分析,您需要确保option不仅仅是类型作为您分配的实际常量,而不是您指定的类型注释

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM