I have the following Typescript types:
export type TeaserOne = { __typename: 'TeaserOne' } & TeaserOneItem;
export type TeaserTwo = { __typename: 'TeaserTwo' } & TeaserTwoItem;
export type TeaserThree = { __typename: 'TeaserThree' } & TeaserThreeItem;
export type Teaser = TeaserOne | TeaserTwo | TeaserThree;
export type FilteredTeasers = Exclude<Teaser, TeaserThree >;
export type TeaserItem = TeaserOneItem | TeaserTwoItem | TeaserThreeItem;
For example the item types looks a bit like:
// TeaserOneItem:
export interface TeaserOneItem {
type: string;
id: string;
title: string;
lead?: string;
}
// TeaserTwoItem:
export interface TeaserTwoItem {
type: string;
id: string;
title: string;
duration?: string;
image?: Image;
}
In a certain React component I need to create a Typescript type guard:
const filteredItems = data.items?.filter(
(item) =>
item?.__typename.includes('TeaserOne') || item?.__typename.includes('TeaserTwo')
);
// --> Maybe also I can refactor above with a type guard, but how exactly?
{filteredItems.map((node, index) => {
if (isTeaserOne() // <-- Here I want to use a type guard) {
const teaserOne = node as TeaserOneType;
return (
<TeaserOne
key={teaserOne.id}
title={teaserOne.title}
lead={teaserOne.lead}
/>
);
}
const teaserTwo = node as TeaserTwoType;
return (
<TeaserTwo
key={teaserTwo.id}
title={teaserTwo.title}
image={teaserTwo.image}
/>
);
})}
How do I create a nice and clean type guard function isTeaserOne()
? So far I have:
const isTeaserOne = (teaser: TeaserItem): teaser is TeaserOneItem =>
typeof teaser === 'object' && teaser.type.includes('TeaserOne');
But how do I have to use this? Or do I have to refactor above type guard function?
CodePudding user response:
In your code isTeaserOne = (teaser: Teaser)
use Teaser class, so have the __typename property, you can use it directly
const isTeaserOne = (teaser: Teaser): teaser is TeaserOne => teaser.__typename === 'TeaserOne';
const isTeaserTwo = (teaser: Teaser): teaser is TeaserTwo => teaser.__typename === 'TeaserTwo';
const isTeaserThree = (teaser: Teaser): teaser is TeaserThree => teaser.__typename === 'TeaserThree';
filteredItems.map((node) => {
// here typeof node is Teaser
if (isTeaserOne(node)) {
// here typeof node is TeaserOne
<TeaserOne />
}
if (isTeaserTwo(node)) {
// here typeof node is TeaserTwo
<TeaserTwo />
}
if (isTeaserThree(node)) {
// here typeof node is TeaserThree
<TeaserThree />
}
return "nothing";
})
In fact, is suppose your code is incomplete, beacause in facts you do not need a typeguard here. a simple
if (node.__typename === "TeaserOne") {
// here typeof node is TeaserOne
<TeaserOne />
}
Would give the same results.