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.
[K in K2]where K2 is something other than an array. The resulting type is exactly what I want, but the code doesn't work. This approach loses the physical names of data providers. I could make each provider return their names but I want to keep it DRY.[K1 in K2]bit more and realisedK2is not an array but a union of string values, and a single string could be considered a union with just one one value in the set. Makes more sense now.