Cod*_*ats 3 generics typescript mapped-types
我正在努力解决如何使用TypeScript强力键入某些功能.
本质上我有一个函数接受DataProviders的键/值映射,并返回从每个返回的数据的键/值映射.这是问题的简化版本:
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;
}
Run Code Online (Sandbox Code Playgroud)
目前getDataFromProviders有一个返回类型,any但我想要它,所以如果这样调用...
const values = getDataFromProviders({
ten: { getData: () => 10 },
greet: { getData: () => 'hi' }
});
Run Code Online (Sandbox Code Playgroud)
...然后values将隐式强类型为:
{
ten: number;
greet: string;
}
Run Code Online (Sandbox Code Playgroud)
我想这将涉及返回一个泛型类型与泛型参数,TDataProviders但我不能完全解决它.
这是我能想到的最好但不编译的......
type DataFromDataProvider<TDataProvider extends DataProvider<TData>> = TData;
type DataFromDataProviders<TDataProviders extends DataProviders> = {
[K in keyof TDataProviders]: DataFromDataProvider<TDataProviders[K]>;
}
Run Code Online (Sandbox Code Playgroud)
我正在努力想出一个DataFromDataProvider没有我TData明确作为第二个参数进行编译的类型,我认为我无法做到.
任何帮助将不胜感激.
想象一下,您有一个类型,将提供程序名称映射到提供程序返回的数据类型.像这样的东西:
interface TValues {
ten: number;
greet: string;
}
Run Code Online (Sandbox Code Playgroud)
请注意,您实际上不必定义此类型,只是想象它存在,并将其用作通用参数,名称TValues,无处不在:
interface DataProvider<TData> {
getData(): TData;
}
type DataProviders<TValues> =
{[name in keyof TValues]: DataProvider<TValues[name]>};
function getDataFromProviders<TValues>(
providers: DataProviders<TValues>): TValues {
const result = {};
for (const name of Object.getOwnPropertyNames(providers)) {
result[name] = providers[name].getData();
}
return result as TValues;
}
const values = getDataFromProviders({
ten: { getData: () => 10 },
greet: { getData: () => 'hi' }
});
Run Code Online (Sandbox Code Playgroud)
神奇地(实际上,使用来自映射类型的推断,如@ Aris2World所指出的),typescript能够推断出正确的类型:
let n: number = values.ten;
let s: string = values.greet;
Run Code Online (Sandbox Code Playgroud)
更新:正如问题的作者所指出的,getDataFromProviders在上面的代码中并没有真正检查它接收的对象的每个属性是否符合DataProvider接口.
例如,如果getData拼写错误,则没有错误,只将空对象类型推断为返回类型getDataFromProviders(因此,当您尝试访问结果时仍会出现错误).
const values = getDataFromProviders({ ten: { getDatam: () => 10 } });
//no error, "const values: {}" is inferred for values
Run Code Online (Sandbox Code Playgroud)
有一种方法可以让typescript更早地检测到这个错误,但代价是DataProviders类型定义的额外复杂性:
type DataProviders<TValues> =
{[name in keyof TValues]: DataProvider<TValues[name]>}
& { [name: string]: DataProvider<{}> };
Run Code Online (Sandbox Code Playgroud)
具有可索引类型的交集添加了DataProviders必须与每个属性兼容的要求DataProvider<{}>.它使用空对象类型{}为通用参数DataProvider,因为DataProvider有很好的特性,对于任何数据类型T, DataProvider<T>可以兼容DataProvider<{}>- T是的返回类型getData(),以及任何类型与空对象类型兼容{}.
| 归档时间: |
|
| 查看次数: |
749 次 |
| 最近记录: |