Muteshi
Muteshi

Reputation: 1308

How to use TypeScript union types in react

I am trying to apply types to ReactJS props as implemented in the following interface. AS you can see the type tags is union type

export interface TagInterface {
  id: number;
  name: string;
}

export interface PostInterface {
  tags: TagInterface[] | string[];
}

I have been able to to successfully use this type in a component inside a function as shown

 onClick={() => handleClick(post.tags[0] as string)}

Now when i try to implement this type on another component TypeScript is throwing an error

Property 'name' does not exist on type 'string | TagInterface'.
  Property 'name' does not exist on type 'string'.
useEffect(() => {
    const getPostData = async () => {
      const { data: posts }: DataInterface = await getRelatedPosts(
        post.tags[0].name // this produces an error
      );
      setRelatedPosts(posts.results);
    };
    getPostData();
  }, []);

How can I properly set the type from the union type?

Upvotes: 1

Views: 1226

Answers (1)

Lesiak
Lesiak

Reputation: 25936

Property name is not common to string and TagInterface. Thus, you need to have two code paths for two cases:

  • tag is a string
  • tag is a TagInterface

TS will try to analyze your code and give you access to most precise type it inferred. The process is called Narrowing, and in some cases it can be fully transparent, and in some cases you need to check what is the actual type of the object you are dealing with.

In case of string | TagInterface union, the most straightorward approach is a typeof type guard.

interface TagInterface {
  id: number;
  name: string;
}

function getName(tag: TagInterface | string) {
  if (typeof tag === 'string') {
    return tag;
  } else {
    return tag.name;
  }
}

console.log(getName('stringTag'));
console.log(getName({
  id: 1,
  name: 'tagInterfaceTag'
}));

Type assertion that you used in your onclick handler: post.tags[0] as string is not a solution. With this assertion, you force TS to treat tag as a string - it will fail at runtime if it is not.

Playground link

Upvotes: 3

Related Questions