lal12
lal12

Reputation: 131

Map an objects type in typescript

I am looking for a way of a "mapped" object type in typescript.

I have a the following typings:

interface Factory<T>{
     serialize: (val: T)=>void,
     deserialize: ()=>T,
}
interface MyDict{
     [key: string]: Factory<any>
}

function deserialize(dict: MyDict){
     let mapped = {};
     for(let k in dict){
          mapped[k] = dict[k].deserialize();
     }
     return mapped;
}

What I want is that the return type of map is correctly determined.

So when doing this:

let mapped = map({
    foo: {deserialize: ()=>'hello world'}, 
    foo2: {deserialize: ()=>123}, 
    foo3: {deserialize: ()=>({foo4: 'foo4'})}
});

mapped should be typed as {foo: string, foo2: number, foo3: {foo4: string}}.

Upvotes: 1

Views: 115

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249636

You can do this using a mapped type. The function will also need to be generic in order to capture the actual type of the argument:

interface Factory<T>{
     serialize?: (val: T)=>void,
     deserialize: ()=>T,
}
interface MyDict{
     [key: string]: Factory<any>
}

type FactoryReturnType<T extends MyDict> = {
    [K in keyof T]: ReturnType<T[K]['deserialize']>
}

function deserialize<T extends MyDict>(dict: T){
     let mapped = {} as FactoryReturnType<T>;;
     for(let k in dict){
          mapped[k] = dict[k].deserialize();
     }
     return mapped;
}

let mapped = deserialize({
    foo: {deserialize: ()=>'hello world'}, 
    foo2: {deserialize: ()=>123}, 
    foo3: {deserialize: ()=>({foo4: 'foo4'})}
});

mapped.foo3.foo4

Playground Link

Upvotes: 2

Related Questions