0

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) '
MaximoConn
  • 31
  • 6

2 Answers2

1

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.

Arshia Moghaddam
  • 440
  • 6
  • 19
  • Thank you very much @Arshia That did work very well, and I'll definitely check how it worked in the full explanation – MaximoConn Dec 25 '22 at 12:17
0
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
}
Dimava
  • 7,654
  • 1
  • 9
  • 24
  • hey @Dimava thanks for reply, but can you please give a little explanation since this code is a bit above my level :D – MaximoConn Dec 24 '22 at 11:28