gib
gib

Reputation: 788

How to return typed object based on function argument array?

I have a function which converts array values into keys in a object:

function x(keys: string[]) {
  const obj: any = {};
  keys.forEach(v => {
    obj[v] = 'somevalue...';
  });
  return obj;
}

const result = x(['a', 'b', 'c']);
console.log(result); // {a: "somevalue...", b: "somevalue...", c: "somevalue..."}

Is it possible to tell TypeScript that return value of this function will be {<values of array>: string} ?

Upvotes: 4

Views: 103

Answers (2)

k0pernikus
k0pernikus

Reputation: 66480

Since typescript's typings are only available at compile-time, there is no way for it to infer that information at runtime, esp. if the array is dynamically created. (If your keys are constant, have a look at Titian's solution.)

For typescript, your array is an array of strings.

You can type your returned object of the x function with the index signature to avoid the any type hint:

const obj: {[key: string]: string} = {};

Yet keep in mind that it won't check for the existence of a key.

So the compiler will think that

const exists = obj["a"];
const doesntExists = obj["junk"];

are okay. You still have to check for undefined values.

Upvotes: 2

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249506

If your function is mostly called with constants, it makes sense to use a generic type parameter to capture the actual strings passed into the function in a generic type parameter. You can the use this type parameter with record to get a strongly typed object that will have the keys you specified.

function x<K extends string>(keys: readonly K[]) {
  const obj = {} as Record<K, string>;
  keys.forEach(v => {
    obj[v] = 'somevalue...';
  });
  return obj;
}

const result = x(['a', 'b', 'c']); //  Record<"a" | "b" | "c", string>, same as {a: string, b: string, c: string}
result.a;
const keys = ['a', 'b', 'c'] as const
const result2 = x(keys);//  Record<"a" | "b" | "c", string>

const skeys = ['a', 'b', 'c']// string[]
const result3 = x(keys);//  Record<string, string>, same as { [n: string]: string }

Play

If the function is called with an array that contains string you will get a plain index signature so you will not be worse off with this version.

Upvotes: 2

Related Questions