typescript 如何有条件地从多个选项( prop )中只输入一个选项

jtw3ybtb  于 2022-12-27  发布在  TypeScript
关注(0)|答案(2)|浏览(170)

我有一个 prop 看起来像:

{
option1,
option2,
option3,
option4,
general,
otheprops
}

我想要的是使它只有一个选项可以使用在给定的时间我有什么作为类型:

interface MyTypes {
 option1: boolean
 option2: boolean
 option3: boolean
 general: boolean
 otherprops: string
}

我想做的是:

interface GeneralTypes{
 general: boolean
 otherprops: string
}

interface Option1Types{
 option1: boolean
}
interface Option2Types{
 option2: boolean
}
interface Option3Types{
 option3: boolean
}
 
type MyTypes = GeneralTypes & ( Option1Types | Option2Types |Option3Types )

但我得到这个错误

Property 'option1' does not exist on type '(GeneralTypes & Option1) | (GeneralTypes & Option2)| (GeneralTypes & Option3) '
Property 'option2' does not exist on type '(GeneralTypes & Option1) | (GeneralTypes & Option2)| (GeneralTypes & Option3) '
Property 'option3' does not exist on type '(GeneralTypes & Option1) | (GeneralTypes & Option2)| (GeneralTypes & Option3) '
az31mfrm

az31mfrm1#

下面是我在只需要设置其中一个属性时的发现。

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]

interface GeneralTypes {
  general: boolean
  otherprops: string
}

type MyTypes = GeneralTypes & RequireOnlyOne<{
  option1: boolean,
  option2: boolean,
  option3: boolean,
}>

const props: MyTypes = {
  general: false,
  otherprops: '',
  option1: true,
}

有一个完整的解释here

yzuktlbb

yzuktlbb2#

type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

type DistinctUnion<T> =
  | UnionToIntersection<T> extends infer X ? ( // save to var X
    T extends any ? // split by '|'
    T & { [k in Exclude<keyof X, keyof T>]?: never } // add missing keys as ?:never
    : never
  ) : never

type x = DistinctUnion<MyTypes>
// type x = (GeneralTypes & Option1Types & {
//     option2: never;
//     option3: never;
// }) | (GeneralTypes & Option2Types & {
//     option1: never;
//     option3: never;
// }) | (GeneralTypes & ... 1 more ... & {
//     ...;
// })

declare let a: x;
if (a.option1) {
  a; // GeneralTypes & Option1Types
}

相关问题