打字稿中的索引签名如何工作?

时间:2017-10-31 14:27:21

标签: angular typescript

尝试设置对象索引签名时,我有一个错误的重复数字索引签名。以下是工作示例click here

    export class HelloComponent implements OnInit  {
      //works
      watched: { [id: number]: boolean } = {} ; //works
      //doesnt work
      watchedOne: { [id: number]: boolean, 
        [fid: number]: boolean } = {} ; // Doesn't Work
      constructor() {}

      watch(talk): void {
        console.log('watch', talk.id);
        this.watched[talk.id] = true;
        this.watchedOne[talk.id] = true; // error
        console.log('watch-obj', this.watched); 
    }
     ngOnInit() {
        this.watch({
          id: 9,
          fid: 4
        });
     }
    }

2 个答案:

答案 0 :(得分:3)

请仔细阅读The TypeScript Handbook和/或TypeScript Deep Dive中有关索引签名的部分。

可能它没有明确为什么你想要一个索引签名。如果要定义类型并且知道所关注的属性集(包括键名),则不需要索引签名。当有人访问没有索引签名的对象并使用未知密钥,或者使用未知密钥分配新对象文字时,它是编译器错误:

const foo: {bar: boolean, baz: boolean} = {
  bar: true, 
  baz: false, 
  qux: false // error, extra property not expected
};
foo.bar;
foo.baz;
foo.qux; // error, no idea what qux is supposed to be
foo.quux; // error, no idea what quux is supposed to be

在上面的代码中,barbaz被接受,但qux上出现了错误。

相反,如果您想要允许任何键,而不事先知道它是什么,那么您可以添加索引签名:

const foo: {bar: boolean, baz: boolean, [k: string]: boolean | undefined} = {
  bar: true, 
  baz: false, 
  qux: false // no error
};
foo.bar;
foo.baz;
foo.qux; // boolean | undefined
foo.quux; // boolean | undefined

使用单个索引签名,您可以根据需要设置具有正确类型的键和值的多个属性。您在签名中给出索引键的名称根本不重要;它是任何正确类型键的占位符。密钥的两种可接受类型是stringnumber

例如,使用单个number索引:

const foo: { [k: number]: boolean | undefined } = { };
foo[0] = true;
foo[1] = false;
foo[2] = void 0; // undefined
foo[12345] = true;
foo[54321] = false;
foo[1.5] = true;
foo[-4] = false;

请注意,索引签名中的k并不重要。我通常使用k,但您可以使用keyrandom或其他任何内容,因为它并不重要。它只是一个占位符。

这意味着我可以通过这样的方式使您的上述代码工作:

export class HelloComponent implements OnInit  {
  name: string = "karty";
  watched: { [id: number]: boolean } = {} ;
  // single index signature
  watchedOne: { [id: number]: boolean } = {} ;
  constructor() {}

  // type annotation on talk to ensure the right types
  watch(talk: {id: number, fid: number}): void {
    console.log('watch', talk.id);
    this.watched[talk.id] = true;
    this.watchedOne[talk.fid] = true;
    console.log('watch-obj', this.watched); 
}
 ngOnInit() {
    this.watch({
      id: 9,
      fid: 4
    });
 }
}

希望有所帮助;祝你好运!

答案 1 :(得分:1)

您真的不需要两个对象签名,用于添加具有相同签名的对象。但是,如果您需要添加具有不同签名的对象,则可能需要在声明中添加不同的签名。

以下是具有不同签名声明的示例代码段。此示例代码段可以在 watchedOne 变量中包含数字和字符串(因为字符串包含数字,请参阅下面的@Jcalz评论)

 export class HelloComponent implements OnInit  {
  //works
  watched: { [id: number]: boolean } = {} ; //works
   //works now
  watchedOne: {[fid: string]: boolean } = {} ; // Here variable name( like fid) doesn't really matter
  constructor() {}

  watch(talk): void {
    console.log('watch', talk.id);
    this.watched[talk.id] = true;
    this.watchedOne[talk.id] = true; // no error here now
    this.watchedOne[talk.fid] = true; //no error , 
    this.watchedOne[talk.str] = true; //no error
    console.log('watch-obj', this.watched); 
    console.log('watch-one-obj', this.watchedOne);  // this works fine
}
 ngOnInit() {
    this.watch({
      id: 9,
      fid: 4,
      str:"hello"
    });
 }
}