2

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?

1 Answer 1

2

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');
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.