I have an object, whose keys' types can be string | number | boolean
. In order to update this object I have an abstract function that accepts two parameters:
key
: to target a specific key of the objectvalue
: to update the value of the aforementionedkey
.
The function looks like this:
// interface
interface Frequency {
frequency: "daily" | "monthly";
sendHour: number;
sendMinutes: number;
sendDay: number;
delayStart: boolean;
}
// react state
const [frequency, setFrequency] = useState<Frequency>({
frequency: "daily",
sendHour: 1,
sendMinutes: 1,
sendDay: 1,
delayStart: false,
});
// updater
const onChangeFrequency = (
key: keyof Frequency,
value: string | number | boolean
) => {
setFrequency((frequency) => ({
...frequency,
[key]: value,
}));
};
It works, but it also means I coud overwrite a boolean with a number, and typescript would not catch the error. How to make sure the value I enter always match the key's type?
CodePudding user response:
You can do this with generics if you're using a literal for the key when calling onChangeFrequency
:
const onChangeFrequency = <KeyType extends keyof Frequency,>(
// −−−−−−−−−−−−−−−−−−−−−−−^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
key: KeyType,
// −−−−−−^^^^^^^
value: Frequency[KeyType]
// −−−−−−−−^^^^^^^^^^^^^^^^^^
) => {
setFrequency((frequency) => ({
...frequency,
[key]: value,
}));
};
onChangeFrequency("sendHour", 20); // Works
onChangeFrequency("sendHour", "daily"); // Error as desired
(The ,
at the end of the generic is just in case you're doing this in a .tsx
file; it differentiates between generic parameter syntax and JSX element syntax.)