TypeScript Generics

Viewed 2430

I'm struggling with how to strongly type some functionality with TypeScript.

Essentially I have a function that accepts a key/value map of DataProviders and returns a key/value map of the data returned from each. Here's a simplified version of the problem:

interface DataProvider<TData> {
    getData(): TData;
}

interface DataProviders {
    [name: string]: DataProvider<any>;
}

function getDataFromProviders<TDataProviders extends DataProviders>(
    providers: TDataProviders): any {

    const result = {};

    for (const name of Object.getOwnPropertyNames(providers)) {
        result[name] = providers[name].getData();
    }

    return result;
}

Currently getDataFromProviders has a return type of any but I want it so that if called like so...

const values = getDataFromProviders({
    ten: { getData: () => 10 },
    greet: { getData: () => 'hi' }
});

...then values will be implicitly strongly typed as:

{
    ten: number;
    greet: string;
}

I imagine this would involve returning a generic type with a generic parameter of TDataProviders but I can't quite work it out.

This is the best I can come up with but doesn't compile...

type DataFromDataProvider<TDataProvider extends DataProvider<TData>> = TData;

type DataFromDataProviders<TDataProviders extends DataProviders> = {
    [K in keyof TDataProviders]: DataFromDataProvider<TDataProviders[K]>;
}

I'm struggling coming up with a DataFromDataProvider type that compiles without me passing in TData explicitly as a second parameter, which I don't think I can do.

Any help would be greatly appreciated.

1 Answers
Related