为什么下面的代码会导致ts(2411)错误?
class Greeter {
[key: string]: string | number[];
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet(): string {
return "Hello, " + this.greeting;
}
}
错误发生在greet(),它说type '() => string'不能分配给type 'string | number[]'。
如果我将object添加到索引签名中,错误就会消失。为什么会这样呢?
另外,对于索引签名,它是否使用了any的不良实践?
编辑:我还在签名中添加了接口Function。它也能用。不过,问题是为什么。
发布于 2019-03-07 23:23:02
类或具有索引签名的接口中声明的任何属性或方法必须具有与索引中的类型兼容的类型。这就是将Function添加到索引签名中的原因。
原因是在文件中解释
虽然字符串索引签名是描述“字典”模式的一种强大方法,但它们也强制要求所有属性都与其返回类型匹配。这是因为字符串索引声明
obj.property也可以作为obj["property"]使用。在下面的示例中,name的类型与字符串索引的类型不匹配,类型检查器提供了一个错误:
interface NumberDictionary {
[index: string]: number;
length: number; // ok, length is a number
name: string; // error, the type of 'name' is not a subtype of the indexer
}将any添加到索引器签名可能被认为是一种不好的做法,因为any禁止类型选择,而从any以任何方式获得的任何值也具有any类型,除非另有显式声明,因此使用any会增加出现编译器未报告的类型错误的可能性。
将Function添加到该类型更好,因为它正确地描述了类中包含的实际数据--当您使用索引访问获得如下值时
const key = 'greeting';
const value = this[key];如果key恰好等于'greet',您可能会得到一个作为值的函数。此外,当您将字符串值赋值给greet时
this['greet'] = 'hi!';该方法将被一个字符串值覆盖,您将无法再调用它。
考虑到所有这些,最好将带有索引签名的字典保存在类的单独属性中,而不是在类本身中。像这样的东西可以起作用:
class Greeter {
data: { [key: string]: string | number[] } = {};
get greeting(): string { return this.data.greeting.toString() }
set greeting(value: string) { this.data.greeting = value };
constructor(message: string) {
this.greeting = message;
}
greet(): string {
return "Hello, " + this.greeting;
}
}发布于 2020-10-17 19:08:49
有一个解决办法可以让你做到这一点。在我的例子中,我希望有一个具有索引签名的类,外加一个自定义设置器和一个返回所有值的属性all (这样我就可以在使用该类时避免丑陋的Object.values )。
这是一个例子。
interface IAccessor<T> {
[key: string]: T;
}
interface IGetter<T> {
all: T[]
}
class Accessor<T> {
get all(): T[] {
return Object.values<T>(this);
}
[key: string]: T | any; // any will do the trick, but it's not enough
}
const accessor: IAccessor<string> & IGetter<string> = new Accessor<string>();
accessor.first = "a";
accessor.second = "b";
accessor.third = "c";
console.log(accessor.all); // ["a", "b", "c"]https://stackoverflow.com/questions/55054226
复制相似问题