I have a React TypeScript component which accepts multiple props of which some are optional and these include functions as well. Below is a rough example of what my actual code looks like
interface AnimalProps {
animalName: string;
bark?: () => void;
swim?: () => void;
}
const Animal = ({ animalName, bark, swim }: AnimalProps) => {
/* some rendering here */
}
I also call the bark or swim function depending upon the animalName
.
The issue is since both of these are optional props, typescript keeps throwing the error
Cannot invoke an object which is possibly undefined
. How can I assert to the compiler that at least one of these function will definitely be passed depending upon the animalName
?
CodePudding user response:
You can simply check if the function
exists before calling it.
if (animalName === 'dog' && typeof bark === 'function') {
bark();
}
If you feel like that is too verbose, you can also take advantage of optional-chaining to do the same thing.
if (animalName === 'dog') {
bark?.(); // Will only invoke bark() if it's defined
}
Optional-chaining is supported in TypeScript since version 3.7.
CodePudding user response:
Apart from the suggested solutions, you may also use discriminating unions: link to the doc which is designed specifically to solve this kind of situations (refer the doc).
like this:
type DogProps = {
animalName: "dog";
bark: () => void;
}
type FishProps = {
animalName: "fish";
swim: () => void;
}
type AnimalProps = DogProps | FishProps;
const Animal = (props: AnimalProps) => {
if(props.animalName === 'dog') {
props.bark();
} else {
props.swim();
}
}
TS Playground link: https://tsplay.dev/NddryN
Destructing isn't possible until you narrow down the type like this (you see other props resolve appropriately without hassle of checking):
type DogProps = {
animalName: "dog";
bark: () => void;
dogProp: string;
}
type FishProps = {
animalName: "fish";
swim: () => void;
fishProp: number;
}
type AnimalProps = DogProps | FishProps;
const Animal1 = (props: AnimalProps) => {
if(props.animalName === 'dog') {
const { bark, dogProp } = props;
bark();
} else {
const {swim, fishProp} = props;
swim();
}
}
see this: https://tsplay.dev/N9pn7w