Issue
I am trying to create a function that takes in a key and a value and updates that corresponding key-value pair on a typed object. Here is a basic example of what I am after.
Link to code sandbox with below code
type x = {
prop : number,
other : string
}
let dataToUpdate : x = {
prop: 1,
other: "string"
}
function updateKey(key : string, value : number | string) {
dataToUpdate[key] = value;
}
I am getting this error with the above implementation.
Element implicitly has an
'any'type because expression of type'string'can't be used to index type'x'. No index signature with a parameter of type'string'was found on type'x'.(7053)
Update I was introduced to the idea of an XY Problem. Below is the actual implementation I am after. I am trying to create a context within React that returns a function that allows you to only update a specific property within the object that is stored in the context
export function StoreProvider(props: any) {
const [storeData, setStoreData] = useState<StoreData>(initProviderData);
function setStoreKeyValue(keyToUpdate: keyof StoreData[], valueToSet: boolean | string | number | null){
let newStoreData = {...storeData);
const isStoreData = Object.keys(initProviderData).filter((key) => { key == keyToUpdate }).length > 1;
if (isStoreData && newStoreData) {
newStoreData[keyToUpdate] = valueToSet;
setStoreData(newStoreData)
}
}
return (
<StoreContext.Provider value={{ "storeData": storeData, "setStoreData": setStoreData }}>
{props.children}
</StoreContext.Provider>
)
}
Solution
TLDR;
updateKey<K extends keyof X>(key: K, value: X[K]) {
dataToUpdate[key] = value;
}
Details:
Given
type X = {
prop: number;
other: string;
};
const dataToUpdate: X = {
prop: 1,
other: "string"
};
TypeScript does not allow us to access properties of a well-typed object with a known set of properties, such as your dataToUpdate, via an arbitrary property key type such as string.
As the language knows that the only keys of dataToUpdate are "prop" and "other", the key parameter of your update function must be restricted accordingly.
While we could write out the union type explicitly in the parameter list, key: "prop" | "other", this pattern is so fundamental to JavaScript that TypeScript provides the keyof type operator which produces a union type of all the property keys of a given type, allowing us to write
updateKey(key: keyof X, value: string | number) {
dataToUpdate[key] = value;
}
However, we're not done yet because the language needs to ensure that the type of the value parameter corresponds to the property type of the specified key and, as it happens, "prop" must be a number and "other" must be a string.
To describe this we adjust our declaration as follows
updateKey<K extends keyof X>(key: K, value: X[K])
What we've done is associate the types of the two parameters such that the type of value matches the type of the property specified by key, whenever the function is called.
Answered By - Aluan Haddad
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.