使用具有区别联合的Typescript类型交叉时出现意外类型错误

问题描述 投票:1回答:1

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_True,尽管discriminant_1false,并且说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'.

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

是否有可能以这样的方式编写类型:构造错误类型时返回的错误消息指向正确的缺失字段?

typescript
1个回答
0
投票

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

我不确定那些受歧视的工会能不能给你带来你在这里所拥有的一切。用户定义的类型保护可以。让我解释。你的对象大致是这样的:

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

但是你想要更多地强制执行这些类型。因此,让我们忘记discriminant_2extra_field_2?存在来简化问题。噗!他们走了。

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,那么它可能适合您的需求吗?希望有所帮助。吉达说“嗨”:-)

© www.soinside.com 2019 - 2024. All rights reserved.