Home > Blockchain >  How to conditionally type only one choice to work from multi options (props)
How to conditionally type only one choice to work from multi options (props)

Time:12-25

i have a props that looks like:

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

what i want is to make it that only only one option can be used at giving time what i have as types :

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

What i tried to do is:

interface GeneralTypes{
 general: boolean
 otherprops: string
}

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

but i get this error

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) '

CodePudding user response:

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
}

CodePudding user response:

here is what I've found when I need only one of the properties to be set.

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,
}

there is a full explanation here.

  • Related