打字稿:在条件语句中使用条件类型 [英] Typescript: using conditional typing in conditional statements

查看:37
本文介绍了打字稿:在条件语句中使用条件类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一些联合类型:

Assume I have some a-lot-of-union type:

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

其中 MyType{N} 具有这种签名:

where MyType{N} has this kind of signature:

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

我知道我可以使用一种类型保护函数,例如.:

I know that I can use a kind of type guard function, e. g.:

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

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

but in this case I should write a lot of this kind of functions.

那么,问题是:我可以在条件语句(if ... elseswitch ... case)中动态定义类型吗?例如:

So, the question is: can I dynamically define type inside a conditional statements (if ... else or switch ... case)? For example:

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() 实现中不需要.

If you plan to check a union-typed value with a switch/case statement, you should probably make it a disciminated union where the type property of each constituent of the union is declared to be the relevant string literal instead of just string. You don't really need conditional types to deal with this, at least not inside your someFunction() implementation.

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

For example, let's say your types look like this:

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"] 上的检查视为类型保护,如下所示:

Then the compiler will automatically treat checks on MyComplexType["type"] as a type guard, like this:

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
    }
}

exhaustivenessCheck() 基本上是一个 throw 语句,如果函数以某种方式失败到 default.这不应该发生,但有用的是,如果编译器认为您没有检查所有内容,它会警告您.那是因为 exhaustivenessCheck() 要求其参数的类型为 never,这是不可能发生的.如果您注释掉 case "type3" 子句,或者稍后向 MyComplexType 联合添加一个新成分,exhaustivenessCheck() 行将抛出错误,说明您未能检查案例.

That exhaustivenessCheck() is basically a throw statement if the function somehow falls through to default. That shouldn't happen, but the usefulness is that the compiler will warn you if it doesn't think you checked everything. That's because exhaustivenessCheck() requires its parameter to be of type never, which can't happen. If you comment out the case "type3" clause, or sometime later add a new constituent to the MyComplexType union, the exhaustivenessCheck() line will throw an error saying you failed to check a case.

此时您可以停止,但如果您的类型真的是程序化的,因为它们只包含两个属性,一个 type 判别字符串和一个 data 属性,那么您可以像这样以更少的重复定义您的类型:

At this point you could stop, but if your types are really that programmatic in that they contain just two properties, a type discriminant string and a data property, then you can define your types with less repetition like this:

// 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 是否扩展为我上面定义的 MyComplexType 联合.您的旧 MyType1 现在是 MyType<"type1">,依此类推.也就是说,如果您需要为类型使用旧名称,您可以这样做:

You can verify that MyType or MyType<keyof MyTypes> expands to the MyComplexType union I defined above. Your old MyType1 is now MyType<"type1">, and so forth. That is, if you need to use your old names for the types you can do it like this:

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

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

Hope that helps; good luck!

这篇关于打字稿:在条件语句中使用条件类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆