Reputation: 1308
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
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.
Upvotes: 3