I've constructed the function that accepts an object and a key of that object that is a string. But in the body of the function it will not let me set the value of the object with a different string.
const setAndGetString = <K extends string, T extends Record<Exclude<string, K>, any>>(
obj: T & Record<K, string>,
key: K
): string => {
obj[key] = "foo" // Type 'string' is not assignable to type '(T & Record<K, string>)[K]'.
return obj[key] // okay
}
Is there a way to adjust the signature so that the assignment will work? (yes, I can cast in the assignment, but that solution isn't great).
CodePudding user response:
You were close.
Consider this example:
/**
* Obtain a union of all values of record
*/
type Values<T> = T[keyof T]
/**
* Obtain a union of all object keys which coresponds to strings
*/
type StringProperty<T> = Values<{
[Prop in keyof T]: T[Prop] extends string ? Prop : never
}>
const setAndGetString = <
Obj extends Record<PropertyKey, unknown>,
Key extends StringProperty<Obj>
>(obj: Obj & Record<Key, string>, key: Key) => {
const result = obj[key].charAt // ok
return obj[key] // okay
}
const obj = {
a: 'a',
b: 42
}
setAndGetString(obj, 'a') // ok
setAndGetString(obj, 'b') // expected error