I do this normally in JavaScript:
function setArbitraryProperty(object, field, value) {
object[field] = value;
}
Now how do I do this in TypeScript?
function setArbitraryPropertyTS(object: MyXType, field: string, value: unknown): void {
object[field] = value;
}
I get:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'MyXType'.
No index signature with a parameter of type 'string' was found on type 'MyXType'.
If I try using keyof
:
function setArbitraryPropertyTS(object: MyXType, field: keyof MyXType, value: unknown): void {
object[field] = value;
}
I get:
Type 'unknown' is not assignable to type 'never'.
How do I get this to work? I would simply like to create a generic function which sets an arbitrary property on a typed object, where that "arbitrary property" is a property that is explicitly defined on the object. So I basically want to use it like this:
type MyXType = {
a: string;
b: number;
c: boolean;
}
const obj1 = { a: 'foo', b: 123, c: true };
setArbitraryPropertyTS(obj1, 'a', 'bar');
In my case, my setArbitraryPropertyTS
is actually a quite complex function which does a whole bunch of stuff, finally updating the property, and I want to vary the logic in a bunch of different ways depending on the property I am setting. So I might have:
setArbitraryPropertyTS(obj: MyXType, field: keyof MyXType, val: unknown): void {
// complex logic...
obj[field] = val;
}
setA(obj: MyXType): void {
// complex logic...
const val = 'foo' // retrieved from logic...
setArbitraryPropertyTS(obj, 'a', val);
}
setB(obj: MyXType): void {
// complex logic...
const val = 123 // retrieved from logic...
setArbitraryPropertyTS(obj, 'b', val);
}
setC(obj: MyXType): void {
// complex logic...
const val = true // retrieved from logic...
setArbitraryPropertyTS(obj, 'c', val);
}
Any way this is possible?
CodePudding user response:
You'll need generics. Declare the object as a generic type, the field as another that's a key of the object type, and the value as something assignable to that key of the object.
function setArbitraryPropertyTS<
T extends object,
F extends keyof T,
V extends T[F]
>(
object: T,
field: F,
value: V
) {
object[field] = value;
}
const obj1 = { a: 'foo', b: 123, c: true };
setArbitraryPropertyTS(obj1, 'a', 'bar');