代码如下:
function id<T>(x: T) {
return x
}
const keys: string[] = []
const obj1 = Object.fromEntries(keys.map(k => [
k,
{test() {}} // OK
]))
const obj2 = Object.fromEntries(keys.map(k => [
k,
id({test() {}}) // Error
]))
const obj3 = Object.fromEntries(keys.map(k => [
k,
id({test: new Date()}) // OK
]))
我不知道为什么打字稿会出现这个错误:
Argument of type '{ test(): void; }' is not assignable to parameter of type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to '{ test(): void; }'.
似乎只有对象字面量中的函数会导致此错误。
此处的 id
函数仅用于演示。实际函数具有此签名:
<T>(x: T) => T & SomeExtraFields
打字稿版本:4.2.3
答案 0 :(得分:1)
您有多种处理方法:
首先:
如果你使用引用而不是文字类型,它会按预期工作:
const id = <T,>(x: T): T => x
const keys: string[] = []
const iter = keys.map(k => [
k,
id({ test() { } }) // ok
])
const obj2 = Object.fromEntries(iter)
或:
const idResult = id({ test() { } })
const obj2 = Object.fromEntries(keys.map(k => [
k,
idResult
]))
第二
让我们尝试使用箭头函数作为属性而不是方法:
const obj2 = Object.fromEntries(keys.map(k => [
k,
id({ test: () => { } }) // ok
]))
奇怪的行为,不是吗?
让我们来看看 Object.fromEntries
签名:
fromEntries<T = any>(entries: Iterable<readonly [PropertyKey, T]>): { [k: string]: T };
因此,TS 尝试推断 T
泛型类型。在我们的例子中,它是 ReturnType
的 id function
。
但是由于某些原因,TS 做不到。
第三:
为了帮助 TS 推断类型,您可以为 Array.prototype.map
提供显式泛型参数
const obj2 = Object.fromEntries(
keys.map<[string, { test(): void }]>((k) => [k, id({ test() {} })])
);
第四
您也可以在没有任何显式泛型参数的情况下处理它。
您可以在 T
函数定义中向 id
泛型添加约束。
interface Method {
(): void;
}
const id = <T extends { [prop: string]: Method }>(x: T) => x;
const keys: string[] = [];
const obj2 = Object.fromEntries(keys.map((k) => [k, id({ test() {} })])); // ok
/////////////////////////
type ArrowProp = () => any;
const id = <T extends { [prop: string]: ArrowProp }>(x: T) => x;
const keys: string[] = [];
const obj2 = Object.fromEntries(keys.map((k) => [k, id({ test() {} })]));
第五
你甚至可以使用第二个泛型来帮助 TS 推断类型
const id = <Prop, T extends Record<string, Prop>>(x: T) => x;
// OR
const id = <T extends object>(x: T) => x;
const keys: string[] = [];
const obj2 = Object.fromEntries(keys.map((k) => [k, id({ test() {} })]));
不幸的是,我无法解释为什么 TS 无法在没有任何解决方法的情况下推断方法属性
答案 1 :(得分:0)
立即尝试。
function id<T>(x: T): T {
return x
}
const keys: string[] = []
const obj1 = Object.entries(keys.map(k => [
k,
{ test() { } } // OK
]))
const obj2 = Object.entries(keys.map(k => [
k,
id({ test() { } }) // Ok
]))
const obj3 = Object.entries(keys.map(k => [
k,
id({ test: new Date() }) // OK
]))