TypeScript (react) : Dynamic update of object with spread operator
The problem is that key
is of type string
, and as you said, may be a string with a name that's not valid in the interface.
If you're always supplying these names as hardcoded values as in your example, you an make it keyof Menu
instead (which also has the convenient effect of TypeScript telling you when you call handleClick
with an invalid value):
const handleClick = (key: keyof Menu) => {
// −−−−−−−−−−−−−−−−−−−−−−−^
If you have to allow string
for key
in handleClick
, then you could use either a type guard function or a type assertion function. Then handleClick
would use it, either in an if
(the type guard) or just inline (the type assertion).
Type guard:
function isValidMenuKey(key: string): key is keyof Menu {
return key === "search" || key === "browse";
}
// ...
const handleClick = (key: string) => {
if (isValidMenuKey(key)) {
return (event: React.MouseEvent) => {
setMenu({...menu, [key]: !menu[key]});
};
} else {
// Do what? (See type assertion version below)
}
};
Type assertion:
// Or type assertion:
function assertIsValidMenuKey(key: string): asserts key is keyof Menu {
if (key !== "search" || key !== "browse") {
throw new Error(`Invalid key for Menu: "${key}"`);
}
}
// ...
const handleClick = (key: string) => {
assertIsValidMenuKey(key);
return (event: React.MouseEvent) => {
setMenu({...menu, [key]: !menu[key]});
};
};