1

I don't know if I'm searching well, but I'd like to do something like a conditional type. I would like to transform this type in my project:

type CommonProps = {
    duration: number;
    type?: 'primary' | 'secondary';
    variant?: 'linear' | 'circular' | 'square'
} 

It should work on a principles: If a primary type has been selected, variant is available: 'linear' | 'circular' | 'square' but if secondary type has been selected, variant is available: 'linear' | 'circular'.

I tried to transform it to:

type CommonProps = {
    duration: number;
}& {
    type?: 'primary'
    variant?: 'linear' | 'circular' | 'square'
} & {
    type?:  'secondary';
    variant?: 'linear' | 'circular'
}

Unfortunately, this does not meet expectations as there is a problem with this use later in the code for example: styles[type][variant];.

1
  • 1
    You are probably looking for discriminated unions Commented Jul 26, 2021 at 15:44

2 Answers 2

3

I'd suggest another solution just using Generics.

type CommonProps<T extends 'primary' | 'secondary'> = {
  duration: number;
  type?: T;
  variant?: T extends 'primary' ? 'linear' | 'circular' | 'square' : T extends 'secondary' ? 'linear' | 'circular' : undefined;
};

const foo: CommonProps<'secondary'> = {
  type: 'secondary',
  variant: 'square' // error square is not part of the variants for secondary
}
Sign up to request clarification or add additional context in comments.

3 Comments

While clever, ths isn't as readable or obvious as the other approach taken by @JaredSmith.
Thank you it is what I was looking for. I even looked at something similar in the documentation, but didn't quite know how to apply it. Thank you again
Yeah that's absolutely true =) That's why I said it's another solution, not the solution ^^
1

You can fix this by discriminating on the type property in the union of two different types:

type PrimaryProps = {
    duration: number;
    type?: 'primary';
    variant?: 'linear' | 'circular' | 'square'
}

type SecondaryProps = {
    duration: number;
    type?: 'secondary';
    variant?: 'linear' | 'circular'
}

function foo(a: PrimaryProps | SecondaryProps) {
  switch (a.type) {
    case 'primary':
      a.variant = 'linear';   // fine
      a.variant = 'circular'; // fine
      a.variant = 'square';   // fine
      a.variant = 'pizza';    // fails as expected
      break;
    case 'secondary':
      a.variant = 'linear';   // fine
      a.variant = 'circular'; // fine
      a.variant = 'square';   // fails, can't have square w/secondary
      break;
  }
}

Playground

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.