1

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?

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

3 Comments

You can overload your function and narrow return type. Example
I am new to react typescript and i was really struggling how to implement a typeguard. This helped alot. Thanks
@Muteshi While not applicable to your original question, take a look at discriminated unions - you're likely to see them a lot.

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.