繁体   English   中英

Typescript:在条件语句中使用条件键入

[英]Typescript: using conditional typing in conditional statements

假设我有很多工会类型:

var MyComplexType = MyType1 | MyType2 | MyType3 | ... | MyTypeN

MyType{N}具有这种签名:

type MyType1 = {
    type: string,
    data: <different data for different types>
}

我知道我可以使用一种类型保护功能,例如:

function isMyComplexTypeOfMyType1(item: MyComplexType): item is MyType1 {
    return item.type == "type of MyType1"
}

但是在这种情况下,我应该编写很多此类函数。

因此,问题是:我可以在条件语句中动态定义类型( if ... else还是switch ... case )? 例如:

function someFunction(item: MyComplexType) {
    switch (item.type) {
        case "type of MyType1":
            // item is MyType1
            // do something
            break
        case "type of MyType2":
            // item is MyType2
            // do something
            break
        ...
    }
}

如果计划使用switch/case语句检查并集类型化的值,则可能应使其成为可区分的并集 ,其中该并集的每个组成部分的type属性都声明为相关的字符串文字,而不是仅是string 您实际上并不需要条件类型来处理此问题,至少不需要在someFunction()实现中进行处理。

例如,假设您的类型如下所示:

type MyType1 = { type: "type1", data: { a: string, b: number } };
type MyType2 = { type: "type2", data: { c: boolean, d: string } };
type MyType3 = { type: "type3", data: { e: number, f: boolean } };

type MyComplexType = MyType1 | MyType2 | MyType3;

然后,编译器将自动将对MyComplexType["type"]检查视为类型保护,如下所示:

const exhaustivenessCheck = (x: never) => x;

function someFunction(item: MyComplexType) {
    switch (item.type) {
        case "type1":
            console.log(2 * item.data.b); // okay
            break;
        case "type2":
            console.log(item.data.d.charAt(0)); // okay
            break;
        case "type3":
            console.log(7 - item.data.e); // okay
            break;
        default:
            throw exhaustivenessCheck(item); // okay
    }
}

如果该函数某种程度上落入default则该exhaustivenessCheck()基本上是throw语句。 那不应该发生,但是有用的是,如果编译器不认为您检查了所有内容,就会警告您。 这是因为exhaustivenessCheck()要求其参数的类型必须是never ,这是不可能发生的。 如果您将case "type3"子句注释掉,或者稍后在MyComplexType联合中添加新的成分,则exhaustivenessCheck()行将引发错误,表明您无法检查案例。


此时,您可以停止操作,但是如果您的类型确实是编程的,因为它们仅包含两个属性( type判别字符串和data属性),那么您可以使用更少的重复来定义类型,如下所示:

// a mapping from type string to data type
type MyTypes = {
    type1: { a: string, b: number };
    type2: { c: boolean, d: string };
    type3: { e: number, f: boolean };
}

// convert the mapping to the union of types
type MyType<K extends keyof MyTypes = keyof MyTypes> = {
    [P in K]: { type: P, data: MyTypes[P] }
}[K]

可以验证MyTypeMyType<keyof MyTypes>扩展为MyComplexType予如上所定义的结合。 您以前的MyType1现在是MyType<"type1"> ,依此类推。 也就是说,如果您需要使用旧名称作为类型,则可以这样操作:

type MyType1 = MyType<"type1">;
type MyType2 = MyType<"type2">;
type MyType3 = MyType<"type3">
type MyComplexType = MyType;

希望能有所帮助; 祝好运!

暂无
暂无

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

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