我有以下代码:
function testFunc<T>(
a: keyof T,
b: keyof T
) {
return function(object2: T): T {
return object2;
}
}
const obj2 = {
a1: 1,
b1: 2,
c1: 3,
e1: 4,
d1: 5
}
const result = testFunc('a1', 'b1')(obj2);
const c1 = result.c1; // Error. Property 'c1' does not exist on type '{ a1: any; } & { b1: any; }'. It's wrong
// We can try this
const result2 = testFunc<typeof obj2>('a1', 'b1')(obj2);
const c12 = result2.c1; // Works great
如何在不显式指定 testFunc (testFunc<typeof obj2>
) 中的类型的情况下从嵌套函数中使用泛型?谢谢。
你可以在这里看到:https://tsplay.dev/mbk7BW
答案 0 :(得分:2)
嗯,类型推断在 TypeScript 中不起作用。只要你调用testFunc('a1', 'b1')
,编译器就已经指定了泛型类型参数T
;没有办法推迟该规范。换句话说:编译器不能 contextually type 从 testFunc('a1', 'b1')
返回的函数基于您继续将 obj2
传递给它的事实。就好像你写了下面的代码:
const returnedFunction = testFunc('a1', 'b1');
/* const returnedFunction: (object2: { a1: any;} & { b1: any;}) =>
{ a1: any; } & { b1: any; } */
const result = returnedFunction(obj2);
/* const result: { a1: any; } & { b1: any; } */
const c1 = result.c1; // oops
returnedFunction
的类型是一个函数,其输入和输出的类型为 {a1: any} & {b1: any}
...,因此 result
的类型为 {a1: any} & {b1: any}
,编译器对此一无所知它的 c1
属性。
为了解决这个问题,我建议更改类型参数,以便 returnedFunction
仍然有足够的信息来执行您想要的操作:
function testFunc<K extends PropertyKey>(
a: K,
b: K
) {
return function <T extends Record<K, any>>(object2: T): T {
return object2;
}
}
这里,testFunc
在 T
中不是通用的,因为 a
和 b
没有包含足够的信息来为 T
生成一个非常有意义的类型({a: any} & {b: any}
是编译器所能做的最好的)。相反,我们在 K
中使其泛型,a
和 b
的键类型的并集。
然后,返回的函数本身在 T
中是泛型的,对于至少具有 K
中的键的对象类型来说是 constrained,但可能更多。
现在当你调用 testFunc('a1', 'b1')
时,结果是强类型的:
const returnedFunction = testFunc('a1', 'b1');
/* const returnedFunction:
<T extends Record<"a1" | "b1", any>>(object2: T) => T */
因此,当您将 obj2
传递给它时,它会执行您想要的操作:
const result = returnedFunction(obj2);
/* const result: {
a1: number;
b1: number;
c1: number;
e1: number;
d1: number;
} */
const c1 = result.c1; // okay, number
既然它在您保存中间结果时有效,您可以停止这样做,它仍然有效:
const result = testFunc('a1', 'b1')(obj2);
const c1 = result.c1; // okay, number