这是一个延续关于解决返回类型的问题 https://stackoverflow.com/questions/53174191/infering-return-type-in-a-nested-object-with-typescript. I'm so接近我想要做的事情(即有一个通用函数来基于经过验证的数据构建模型实例)并且它在 JS 中运行良好,但我无法弄清楚 TS 类型的最终部分。
关键是我的回报Init
类型 - 特别是Builder<T[K]>
部分。我明白为什么会导致Builder<(id: number) => Promise<Test>>
作为返回的类型,但我一生都无法弄清楚如何告诉 TS 事实上它只是Test
被返回,而不是返回 Promise 的函数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();
谢谢你!