我试着创建一个重载函数,一个有两个参数,另一个有一个参数作为对象。它们的用法如下:
// As two parameters
obj.set('a', '123');
obj.set('b', 'efg');
// As a single object parameter
obj.set({ a: '123', b: 'efg' });
然后,我声明重载如下:
export type Fields<T extends BaseModel> = { [K in keyof T['fields']]: T['fields'][K] | typeof BaseModel };
export abstract class BaseModel {
abstract fields: Fields<any>;
// This overload works
set<K extends keyof Fields<this>>(field: K, value: Fields<this>[K]): this;
// This overload throws an error
set<K extends keyof Fields<this>>(fields: { [key: keyof Fields<this>]: Fields<this>[K] }): this;
}
我的单参数overload(作为一个对象)显示这个错误:
“this”类型仅在类或接口的非静态成员中可用。
1条答案
按热度按时间bq3bfh9z1#
问题是索引签名和mapped types看起来很相似,并且可能具有某种相似的效果,但是它们具有不同的规则和不同的效果。
索引签名可以是任何对象类型以及其他属性和签名的一部分,其语法如下
其中
dummyKeyIdentifier
是一个 * dummy * 密钥标识符,因为它仅用于文档目的,并且对于类型系统是不可观察的。对于KeyType
允许是什么存在相当严格的规则;几乎只有string
、number
、symbol
、"pattern"模板文本类型以及这些类型的联合。在示例代码中,不能使用"a"
或3
等字符串/数字文本类型,也不能使用K
等generic type,或涉及表现得像隐式泛型类型参数的多态this
类型的任何类型。因此代码中出现错误。
另一方面,Map类型是独立类型(在大括号内不能存在其他属性或签名),其语法如下
其中
K
是一个 * 泛型类型参数 *,它迭代KeyType
的联合成员,并且在属性类型的范围内。因此,虽然在索引签名中不能再次提及dummyKeyIdentifier
,但可以在Map类型中使用K
,以便为KeyType
中的每个键执行不同的操作。在这里,
KeyType
的规则相当宽松;你仍然可以使用string
,number
,symbol
和模式模板常量(尽管这些最终被转换成了等价的索引签名),但是你也可以使用常量类型和泛型类型以及它们的联合。您可以识别它们之间的区别,因为索引签名在方括号内有冒号(
:
),而Map类型有in
关键字。编译器经常会注意到你在以一种被禁止的方式使用索引签名,并建议你使用Map类型。有时编译器没有意识到Map类型会有帮助,但这仍然是潜在的问题。
在您的情况下,如果将索引签名更改为Map类型:
一切都开始运转。
Playground代码链接