首页 > 解决方案 > 打字稿索引签名和方法

问题描述

为什么下面的代码会ts(2411)出错?

class Greeter {
    [key: string]: string | number[];
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet(): string {
        return "Hello, " + this.greeting;
    }
}

错误是在greet()which 说type '() => string'not assignable to type 'string | number[]'

object如果我添加到索引签名,错误就会消失。这是为什么?

同样对于索引签名,它是否使用any了不好的做法?

Function编辑:我还在签名中添加了界面。它也有效。不过,问题是为什么。

标签: typescript

解决方案


在具有索引签名的类或接口中声明的任何属性或方法必须具有与您在索引中的类型兼容的类型。这就是为什么添加Function到索引签名会有所帮助。

原因在文档中解释

虽然字符串索引签名是描述“字典”模式的强大方式,但它们还强制所有属性与其返回类型匹配。这是因为字符串索引声明 obj.property也可用作obj["property"]. 在以下示例中,名称的类型与字符串索引的类型不匹配,类型检查器会给出错误:

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;
    }
}

推荐阅读