Home > Net >  React - Typescript conditional type assignment
React - Typescript conditional type assignment

Time:12-23

I have to create a component that can be from two different types. Let's say

Type A = { a: SomeCustomType } Type B = { b: SomeOtherDifferentType }

As far I understand, I can define that component type as

function Component<T extends A | B>(props T){ ... Stuff }

And i can call it as

const MyComponent : A = <Component a={"test"}/>
const MyComponent : B = <Component b={1231241}/>

My question here is: when coding Component, how can i navigate props, i need to do:

function Component<T extends A | B>(props T){ 
  let data; 
  if(props typeof A){
    data = props.a 
  }

  if(props typeof A){
    data = props.b 
  }

  console.log(data)
}

I'm not able to use typeof since it's for primitives, but instanceOf seems for classes only. Any clues about this? What i'm doing wrong?

CodePudding user response:

There is no real clean solution for that, since types don't exist in the resulting JavaScript. I'ld advise you do add a shared field like type in both types which helps to TypeScript to figure out which properties are available:


type A = { a: string, type: "A" }
type B = { b: string, type: "B" }

function Component<T extends A | B>(props: T) {
  switch (props.type) { // or: if (props.type === "A") ...
    case 'A':
      // access props.a, TypeScript will infer it's there
      break;
    case 'B':
      // access props.b, TypeScript will infer it's there
      break;
  }
}

The advantage of this approach is that is scales quite well with more - and more complex types.

Edit: In general, type checks can be done with a user-defined type guard:

const isTypeA = (toCheck: A | B): toCheck is A => 'a' in toCheck;

function Component<T extends A | B>(props: T) {
  if (isTypeA(props)) {
    // access props.a, TypeScript will infer it's there
  }
}

But I'ld stick with the first variant in most cases. It's less error prone (the type guard method could be faulty) and delivers the aforementioned advantages.

CodePudding user response:

You could try something like this:

type A = { a: string } 
type B = { b: number }

function Component<T extends A | B>(props: T){ 
  let data; 
  
  if ('a' in props){
    data = props.a 
  } else if ('b' in props){
    data = props.b 
  }
  console.log(data)
}

TypeScript will automatically detect type of props according to checks in if statements. Try in playground

  • Related