这是a question about resolving return types的延续。我 so 接近我要去做的事情(它具有一个通用功能,可以基于经过验证的数据来构建模型实例),并且在JS中可以正常工作,但是我无法确定列出TS输入的最后一部分。
关键是我的Init
类型的返回值-特别是Builder<T[K]>
部分。我知道为什么会导致Builder<(id: number) => Promise<Test>>
作为返回类型,但是我一生无法弄清楚如何告诉TS实际上只是返回Test
而不是返回的函数返回Test
的承诺。
可以将以下内容复制/粘贴到VSCode(或其他任何内容)中以显示问题。 ter1
变量应该是Test
的实例,并且在编译为JS时是,但是TS没有看到。
export interface Builder<T> {
(values: any, db: any): Promise<T>
}
export interface Wrapper {
<T, TId>(
construct: (id: TId, db: any | null) => Promise<T>,
idSrc: string | string[],
errorMsg: string
): Builder<T>
}
let builder: Wrapper = function (construct, idSrc, errorMsg ) {
// A function that can be used to construct the instance
return async function(values: any, db: any | null) {
let id = null;
let inst = await construct(id, db);
if (!inst) {
throw new Error(errorMsg);
}
return inst;
};
}
class Test {
is1 = true;
static async fromId( id: number ) {
var inst = new Test();
// Some async action (e.g. a db read)
return inst;
}
}
class Test2 {
is2 = true;
static async fromId( id: number ) {
var inst = new Test2();
// Some async action (e.g. a db read)
return inst;
}
}
type Config<T extends {}> = {
inputs?: {[index:string]: any},
inst?: T;
};
type Init = <T extends {[key:string]: any}>(
db: any,
config: Config<T>
) => Promise<{[K in keyof T]: Builder<T[K]>}>; // ???
let init: Init = async function ( db, config ) {
let ret: any = {};
if ( config.inst ) {
for (let [key, value] of Object.entries(config.inst)) {
let res = await value( {}, {} );
ret[ key ] = res;
}
}
return ret;
}
async function allan () {
let { ter1, ter2 } = await init( null, {
inst: {
ter1: Test.fromId,
ter2: Test2.fromId
}
} );
console.log( ter1.is1, ter1.is2 ); // should be `true undefined`
// Test `builder` typing
var t1Wrapper = builder( Test.fromId, 'id', 'test');
var t2Wrapper = builder( Test2.fromId, 'id', 'test');
var t1 = await t1Wrapper({}, {});
var t2 = await t2Wrapper({}, {});
t1.is1;
t2.is2;
}
allan();
谢谢!
答案 0 :(得分:2)
看起来您想要的类型如下:
type Unpromise<T extends Promise<any>> = T extends Promise<infer U> ? U : never;
type Init = <T extends { [key: string]: (...args: any[]) => Promise<any> }>(
db: any,
config: Config<T>
) => Promise<{ [K in keyof T]: Unpromise<ReturnType<T[K]>> }>;
但是我还没有花时间浏览所有代码,以了解它是否有意义或者您是否正确实现了它(这真的是minimum example吗?),所以请您原谅我陷入其他问题。
说明:您调用init()
的方式意味着T
应该是一个对象,其属性是返回您所关心的承诺的函数。 (我不确定这些函数的参数类型和数量是否重要)。因此,对于T
中的每个属性,您要提取其返回类型,然后提取promise类型。
Unpromise<T>
使用type inference in conditional types提取承诺值的类型;因此Unpromise<Promise<XXX>>
应该是XXX
。
ReturnType<T>
是type from the standard TypeScript library,它执行类似的操作来获取函数的返回类型;因此ReturnType<()=>XXX>
应该是XXX
。
希望有帮助。祝你好运!
答案 1 :(得分:0)
单位类型是一个返回Promise<{[K in keyof T]: Builder<T[K]>}>
的函数。
相反,它应该只返回一个Promise<{[K in keyof T]: T[K]}>;
。
也在您调用的init函数中
let res = await value( {}, {} );
但是值是Test的fromId函数,它仅接受一个数字参数。