将Typescript的类型交集与已区分的并集一起使用时发生意外的类型错误

时间:2019-04-11 15:45:58

标签: typescript

Playground link

当我尝试同时使用Typescript的类型交集和区分的并集时,我正在运行似乎是错误的类型错误。

想法是:

一个对象应包含两个布尔值-discriminant_1discriminant_2。如果这些判别字段中的任何一个为true,则对象应包含一个额外的字段-分别为extra_field_1extra_field_2

这是有效对象的一些示例:

// Neither field is true - no extra fields
{ discriminant_1: false, discriminant_2: false }

// discriminant_1 is true - extra_field_1 present
{ discriminant_1: true, extra_field_1: true, discriminant_2: false }

// both discriminant fields are true - both extra fields present
{ discriminant_1: true, extra_field_1: true, discriminant_2: true, extra_field_2: true }

还有一个无效的对象,因为discriminant_2true但缺少extra_field_2

{ discriminant_1: false, discriminant_2: true }

这会在预期的位置提供编译错误,但是在没有提供字段的情况下,这些错误会引起混淆。

对于以下对象:

{ discriminant_1: false, discriminant_2: true }

该类型无法编译,因为如果discriminant_2true,则应在对象中指定extra_field_2。但是类型错误是:

Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'FullType'.
  Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'Discriminant1_True & Discriminant2_True'.
    Property 'extra_field_1' is missing in type '{ discriminant_1: false; discriminant_2: true; }' but required in type 'Discriminant1_True'.

该错误消息表示尽管Discriminant1_True & Discriminant2_Truediscriminant_1的事实,但推断出的类型仍然是false,并指出实际上缺少extra_field_1 extra_field_2丢失。

预期的错误消息是:

Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'FullType'.
  Type '{ discriminant_1: false; discriminant_2: true; }' is not assignable to type 'Discriminant1_False & Discriminant2_True'.
    Property 'extra_field_2' is missing in type '{ discriminant_1: false; discriminant_2: true; }' but required in type 'Discriminant2_True'.

这将使程序员指向正确的缺失字段。

是否可以这样编写类型,使得构造错误类型时返回的错误消息指向正确的缺少字段?

1 个答案:

答案 0 :(得分:0)

让我给我2美分,希望比我聪明得多的人( coff @basarat)可以告诉您更多更酷的东西:-)

我不确定受歧视的工会是否能为您提供您所追求的目标。用户定义的类型保护可以。让我解释。您的对象大致如下:

interface NotTheTypeSafetyYouHopedFor { 
    discriminant_1: boolean; 
    extra_field_1?: boolean; 
    discriminant_2: boolean; 
    extra_field_2?: boolean; 
}

但是您想再强制一些类型。因此,我们通过忘记存在discriminant_2extra_field_2?来简化问题。 of!他们走了。

interface False1 { 
    discriminant_1: false; 
}

interface True1 { 
    discriminant_1: true; 
    extra_field_1: boolean; 
}

type False1OrTrue1 = False1 | True1;

const exampleFalse1: False1 = { discriminant_1: false };
const exampleTrue1: True1 = { discriminant_1: true, extra_field_1: false };


function isTrue1(aFalse1OrTrue1: False1OrTrue1): aFalse1OrTrue1 is True1 { 
    return aFalse1OrTrue1.hasOwnProperty('extra_field_1')
}


function doSomething(aFalse1OrTrue1: False1OrTrue1) { 
    if (isTrue1(aFalse1OrTrue1)) {
        console.log(aFalse1OrTrue1.extra_field_1); // succeeds as this is a True1 
    } else { 
        console.log(aFalse1OrTrue1.extra_field_1); // compile error as this is a False1 
    }
}

我怀疑这种方法可能无法直接根据您问题的性质(例如discriminant_2等)进行扩展

但是,如果对象中的每个属性都是False1OrTrue1,那么也许满足您的需求?希望能有所帮助。圭达说“嗨”:-)