如何使用名为"keyof"类型的属性创建对象文本



我什至找不到合适的词来表达这个问题。这是我想要实现的目标的简化代码。

class Test<T, TId extends keyof T> {
public create(id: T[TId]): T {
return {
[TId]: id, // Error here. I want to set property `TId` to value `id`,
} as T;
}
}
interface A {
id: number;
}
interface B {
fileName: string;
}
new Test<A, 'id'>().create(123); // Want to get { id: 123 }
new Test<B, 'fileName'>().create('file'); // Want to get { fileName: 'file' }

错误为:Conversion of type '{ [x: number]: T[TId]; }' to type 'T' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. 'T' could be instantiated with an arbitrary type which could be unrelated to '{ [x: number]: T[TId]; }'.ts(2352)

恐怕您正在尝试做的事情在纯粹的类型中是不可能的。问题就在这里:

new Test<A, 'id'>().create(123); // Want to get { id: 123 }

编译成这个JavaScript:

new Test().create(123);

您可以看到,在这里不可能返回具有正确键的对象,因为您的类型参数('id'(在编译的代码中不存在。运行时不存在类型信息。

要解决此问题,您需要更改该设计,并将'id'作为字符串参数传递给createTest()。例如:

class Test<T extends object, TId extends keyof T = keyof T> {
constructor(private readonly key: TId) { }
public create(value: T[TId]): T {
return { [this.key]: value } as T;
}
}
interface A {
id: number;
}
interface B {
fileName: string;
}
new Test<A>('id').create(123); // Returns { id: 123 }
new Test<B>('fileName').create('file'); // Returns { fileName: 'file' }

它通过自动推断TId进行编译,执行您想要的操作,并强制执行正确的键名称和值(因此filePath作为键或传递数字fileName不会编译(。

最新更新