【问题标题】:Typescript intersection of union and intersection not erroring联合和交集的打字稿交集不出错
【发布时间】:2021-11-26 23:00:55
【问题描述】:

我想要一个类型来确保对象的类型为ABA and B。但是,我认为应该失败的情况之一不是。我确定这很愚蠢,我只是还看不到它。

interface ValueSelector
{
    type: "id" | "value_string"
    value: string
}

interface TemporalSelector
{
    id: number
}

type Selector = (ValueSelector & TemporalSelector) | ValueSelector | TemporalSelector

// Should error
const e0: Selector = {}
const e1: Selector = { id: 0, value: "" }  // <-- does not error
const e2: Selector = { type: "id" }
const e3: Selector = { type: "value_string" }
const e4: Selector = { value: "" }
const e5: Selector = { value: "" }

// Should pass
const a1: Selector = { id: 0 }
const a2: Selector = { type: "id", value: "" }
const a3: Selector = { type: "value_string", value: "" }
const a4: Selector = { id: 0, type: "id", value: "" }
const a5: Selector = { id: 0, type: "value_string", value: "" }

【问题讨论】:

    标签: typescript discriminated-union union-types


    【解决方案1】:

    e1 不会触发错误,因为 { id: 0, value: "" } 已经可以分配给 TemporalSelector,因为它只需要 id 属性。

    为了使其正常工作,您可以使用StrictUnion 助手:

    interface ValueSelector {
        type: "id" | "value_string"
        value: string
    }
    
    interface TemporalSelector {
        id: number
    }
    
    type UnionKeys<T> = T extends T ? keyof T : never;
    type StrictUnionHelper<T, TAll> = 
        T extends any 
        ? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, never>> : never;
    
    type StrictUnion<T> = StrictUnionHelper<T, T>
    
    
    type Selector = (ValueSelector & TemporalSelector) | StrictUnion<ValueSelector | TemporalSelector>
    
    // Should error
    const e0: Selector = {}
    const e1: Selector = { id: 0, value: "" }  // error
    const e2: Selector = { type: "id" }
    const e3: Selector = { type: "value_string" }
    const e4: Selector = { value: "" }
    const e5: Selector = { value: "" }
    
    // Should pass
    const a1: Selector = { id: 0 }
    const a2: Selector = { type: "id", value: "" }
    const a3: Selector = { type: "value_string", value: "" }
    const a4: Selector = { id: 0, type: "id", value: "" }
    const a5: Selector = { id: 0, type: "value_string", value: "" }
    

    Playground

    【讨论】:

    • 这很棒。谢谢你。我通常会忘记这个 Liskov 替换原则/规则。 StrictUnion 正是我所需要的。 tag 属性将不起作用,因为它们允许 AB 但不允许 ABA and B
    • 谢谢。在这种情况下,我也没有考虑 Liskov SP。不错
    猜你喜欢
    • 2022-01-13
    • 2019-07-23
    • 1970-01-01
    • 2020-08-05
    • 2010-10-28
    • 1970-01-01
    • 2012-01-26
    • 2019-04-13
    • 1970-01-01
    相关资源
    最近更新 更多