Rogach
Rogach

Reputation: 27200

Is it possible to map object value types in TypeScript?

For example, I have a function of the following form:

function wrap<T>(item: T): W<T> {
}
interface W<T> {
  item: T;
}

Is it possible to write function (mapValues), that will transform given object values by applying this wrap function and return properly typed object? I understand how to write the actual function (lodash's _.mapValues will work fine), but I don't know if it is possible to apply proper types.

Is it possible to write mapValues function so the following will compile?

interface Before {
  a: number;
  b: string;
}

interface After {
  a: W<number>;
  b: W<string>;
}

let obj1: Before = { a: 1, b: "2" };
let obj2: After = mapValues(obj1);

function typecheck_number(arg: number) {}
function typecheck_string(arg: string) {}
typecheck_number(obj2.a.item);
typecheck_string(obj2.b.item);

Upvotes: 6

Views: 4273

Answers (2)

Rogach
Rogach

Reputation: 27200

Here's one possible solution:

interface W<T> {
  item: T;
}
function mapValues<T>(obj: T): {[K in keyof T]: W<T[K]>} {
  // implementation
}

Unfortunately, similar recursive approach does not seem to be possible, but there is hope that it will be possible with type constraints from this proposal.

This link was very helpful in arriving to this solution: https://blog.mariusschulz.com/2016/05/31/type-queries-and-typeof-in-typescript

Upvotes: 4

Shane
Shane

Reputation: 3199

Yes, your types in the OP are correct. mapValues only needs to be marked to return the type of After.

Here is a TS playground that shows ur example working fine if mapValues was to return a type of After.

The properties of the mapped object are of type Wrap<T>.

Upvotes: 0

Related Questions