Typescript 允许额外属性的StrictUnion

Typescript 允许额外属性的StrictUnion,typescript,typescript-generics,Typescript,Typescript Generics,鉴于此StrictUniongeneric: type UnionKeys<T> = T extends T? keyof T : never; type StrictUnionHelper<T, TAll> = T extends T? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, undefined>> : never; export type Str

鉴于此
StrictUnion
generic:

type UnionKeys<T> = T extends T? keyof T : never;
type StrictUnionHelper<T, TAll> = T extends T? T & Partial<Record<Exclude<UnionKeys<TAll>, keyof T>, undefined>> : never;
export type StrictUnion<T> = StrictUnionHelper<T, T>

type Working = StrictUnion<(
  { id: number } | 
  { uuid: string } | 
  { memberId: number } | 
  { memberUuid: string } | 
  { member: Member } | 
  { organizationId: number, contactId: number })
>

const a: Working = { id: 1 }
const b: Working = { uuid: '123456' }
const c: Working = { organizationId: 1, contactId: 1 }
const d: Working = { organizationId: 1 }
const e: Working = { id: 1, organizationId: 1, contactId: 1 } // I would like this to work
const f: Working = { }
我正在寻找匹配项,以匹配至少一个联合,但也允许额外的属性,这意味着您不能只传递
organizationId
,因为它需要
contactId
,但您可以只传递
id
,而不能传递
empty
{}

如果你使用普通工会的问题是,如果有办法使用普通工会解决这些问题,我会接受这一解决方案

更多想法:

type Requirements = (
  { id: number } | 
  { uuid: string } | 
  { memberId: number } | 
  { memberUuid: string } | 
  { member: Member } | 
  { organizationId: number, contactId: number }
)

✅ Should be valid
❌ Should not be valid

const a: Requirements = { id: 1 } ✅
const b: Requirements = { uuid: '123456' } ✅
const c: Requirements = { id: null, uuid: null } ✅ (will throw, but valid)
const d: Requirements = { uuid: '123456', contactId: 1 } ✅
const e: Requirements = { organizationId: 1, contactId: 1 } ✅
const f: Requirements = { uuid: '12345', organizationId: 1, contactId: 1 } ✅
const g: Requirements = { uuid: null, organizationId: 1, contactId: 1 } ✅
const h: Requirements = { organizationId: 1 } ❌
const i: Requirements = { id: 1, organizationId: undefined } ✅
const j: Requirements = { } ❌
我喜欢
AtLeastOne
的功能:

type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]

你能用普通的工会吗?它本身也不应该允许“{organizationId:1}”。@ProdigySim添加了关于常规联合不起作用的原因的上下文。@ThomasReggi如果
id
在联合的一个组成部分中有效,为什么不直接添加它,即使它是可选的(
{organizationId:number,contactId:number,id?:number}
)。如果您希望允许来自任何成员的成员加入,为什么不使用常规联盟?从上面的代码中,我不清楚你是否可以将
id
从一个连续剧混搭到另一个连续剧中,为什么
StrictUnion
是必要的。@TitianCernicova Dragomir是的,我同意我开始理解我想要的东西的复杂性。1) 我不希望empty起作用,2)我希望需要特定的对(即使它们为null或未定义)。我有
类型AtLeastOne=Partial&U[keyof U]
,但这不适合成对使用。3) 我确实希望额外的
undefined
null
也能正常工作。有什么想法吗?比如说?你能用一个固定的联盟吗?它本身也不应该允许“{organizationId:1}”。@ProdigySim添加了关于常规联合不起作用的原因的上下文。@ThomasReggi如果
id
在联合的一个组成部分中有效,为什么不直接添加它,即使它是可选的(
{organizationId:number,contactId:number,id?:number}
)。如果您希望允许来自任何成员的成员加入,为什么不使用常规联盟?从上面的代码中,我不清楚你是否可以将
id
从一个连续剧混搭到另一个连续剧中,为什么
StrictUnion
是必要的。@TitianCernicova Dragomir是的,我同意我开始理解我想要的东西的复杂性。1) 我不希望empty起作用,2)我希望需要特定的对(即使它们为null或未定义)。我有
类型AtLeastOne=Partial&U[keyof U]
,但这不适合成对使用。3) 我确实希望额外的
undefined
null
也能正常工作。有什么想法吗?比如?
type Requirements = (
  { id: number } | 
  { uuid: string } | 
  { memberId: number } | 
  { memberUuid: string } | 
  { member: Member } | 
  { organizationId: number, contactId: number }
)

✅ Should be valid
❌ Should not be valid

const a: Requirements = { id: 1 } ✅
const b: Requirements = { uuid: '123456' } ✅
const c: Requirements = { id: null, uuid: null } ✅ (will throw, but valid)
const d: Requirements = { uuid: '123456', contactId: 1 } ✅
const e: Requirements = { organizationId: 1, contactId: 1 } ✅
const f: Requirements = { uuid: '12345', organizationId: 1, contactId: 1 } ✅
const g: Requirements = { uuid: null, organizationId: 1, contactId: 1 } ✅
const h: Requirements = { organizationId: 1 } ❌
const i: Requirements = { id: 1, organizationId: undefined } ✅
const j: Requirements = { } ❌
type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]
AtLeastOne<{
    id: number,
    uuid: string,
    memberId: number,
    memberUuid: string,
    member: Member,
    organizationId: number,
    contactId: number
}>
PartialPairs<
  { id: number } | 
  { uuid: string } | 
  { memberId: number } | 
  { memberUuid: string } | 
  { member: Member } | 
  { organizationId: number, contactId: number }
>

AtLeastOne<{
  { id: number } | 
  { uuid: string } | 
  { memberId: number } | 
  { memberUuid: string } | 
  { member: Member } | 
  { organizationId: number, contactId: number }
}>