Typescript:输入可选属性列表中的一个必需属性

RQm*_*man 7 typescript type-definition

我有带有可选属性列表的界面。

export interface OptionalIds {
  entityA_Id?: number;
  entityB_Id?: number;
  entityC_Id?: number;
}
Run Code Online (Sandbox Code Playgroud)

我有一个要求,必须准确定义其中之一。像这样的东西:

export interface RequiredBId {
  entityA_Id?: undefined;
  entityB_Id: number;
  entityC_Id?: undefined;
}

export interface RequiredCId {
  entityA_Id?: undefined;
  entityB_Id?: undefined;
  entityC_Id: number;
}

export interface OptionalIds {
  entityA_Id?: number;
  entityB_Id?: number;
  entityC_Id?: number;
}

export type RestrictedOptionalIds = OptionalIds & (RequiredAId | RequiredBId | RequiredCId)
Run Code Online (Sandbox Code Playgroud)

问题是:是否有其他方法可以在不使用奇怪结构的情况下实现所描述的行为?

Rob*_*ell 2

更新答案

感谢这篇文章RequireOnlyOne/sf/answers/3480763891/

type RequireOnlyOne<T, Keys extends keyof T = keyof T> =
    Pick<T, Exclude<keyof T, Keys>>
    & {
        [K in Keys]-?:
            Required<Pick<T, K>>
            & Partial<Record<Exclude<Keys, K>, undefined>>
    }[Keys]

export interface OptionalIds {
  entityA_Id?: number;
  entityB_Id?: number;
  entityC_Id?: number;
}

const exampleA: RequireOnlyOne<OptionalIds> = {
  entityA_Id: 1
}
const exampleB: RequireOnlyOne<OptionalIds> = {
  entityB_Id: 1
}

const exampleC: RequireOnlyOne<OptionalIds> = {
  entityC_Id: 1
}

// Error
const exampleMultiple: RequireOnlyOne<OptionalIds> = {
  entityA_Id: 1,
  entityB_Id: 2,
}

// Error: {} not assignable to RequireAtLeastOne<OptionalIds, keyof OptionalIds>
const exampleTsError: RequireOnlyOne<OptionalIds> = {

}
Run Code Online (Sandbox Code Playgroud)

原答案

感谢这篇文章RequireAtLeastOne/sf/answers/3480763891/

type RequireAtLeastOne<T, Keys extends keyof T = keyof T> =
    Pick<T, Exclude<keyof T, Keys>> 
    & {
        [K in Keys]-?: Required<Pick<T, K>> & Partial<Pick<T, Exclude<Keys, K>>>
    }[Keys]

export interface OptionalIds {
  entityA_Id?: number;
  entityB_Id?: number;
  entityC_Id?: number;
}

const exampleA: RequireAtLeastOne<OptionalIds> = {
  entityA_Id: 1
}
const exampleB: RequireAtLeastOne<OptionalIds> = {
  entityB_Id: 1
}

const exampleC: RequireAtLeastOne<OptionalIds> = {
  entityC_Id: 1
}

const exampleMultiple: RequireAtLeastOne<OptionalIds> = {
  entityA_Id: 1,
  entityB_Id: 2
}

// Error: {} not assignable to RequireAtLeastOne<OptionalIds, keyof OptionalIds>
const exampleTsError: RequireAtLeastOne<OptionalIds> = {

}
Run Code Online (Sandbox Code Playgroud)