我想有一个类型,以确保一个对象有A
或B
或A 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: "" }
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: "" }
游乐场