Typescript Index Signature

我们讨论接口中的 index signature。

比较全的文章有如下几篇: 官方手册, 以及这篇文章

该特性主要作用是能够让接口包含动态的属性(Properties),比如我们定义一个 person 接口,当然我们之前已经知道一些必要的字段,比如名字性别等等,但是随着时代的变迁,对于person可能还会有一些其他的字段,比如twitter,微博等等。我们不可能在设计 person interface 的时候就包含了所有属性,但是我们可以定一个 index signature, 这样如果我们想加入 twitter, 那么就可以用 ['twiter'] 来添加。

代码如下(代码可以在官方playground运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
interface StringArray {
[index: number]: string;
}
enum Gender {
Male, Female
}

interface Address {
country: string;
province: string;
city: string;
postcode: string;
}

interface Person {
name: string;
sex: Gender;
birthday: string;
addrss: Address;
[key: string]: any; // Must accomodate all members
[index: number]: string; // Can be a subset of string indexer
}
let button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function () {
let person: Person = <Person>{};
person.name = "bob";
person.addrss = { country: "China", province: "Hebei", city: "Baoding", postcode: "1110000" };
person.birthday = "19000909";
person["businessAdress"] = {country:"UK",province:"London",city:"London",postcode:"1110000"}
person["twitter"] = "mengxin";
person[0] = "good";
console.dir(person);

//这个用法是的 非索引签名的属性需要是索引签名的子类型,
// 所以 key 返回的是 any 或者 Addres 的父类,address 才能返回 Address
let test: string = person.twitter;
console.dir(test);

let copyPerson: Person = <Person>{};
copyPerson = person;
copyPerson.name = "Alice";
copyPerson.sex = Gender.Female;
//原有的person的属性也会跟着变化。
console.dir(copyPerson);
}

document.body.appendChild(button);

通过代码我们可以知道,

  1. 这里的 index-signature 的返回值类型可以是任意值any
  2. 我们可以用 ['twitter'].twitter 两种方式访问属性
  3. 由于我们定义了 Address 类型的 address, 所以 index-signature 的返回值必须是any,或者是 Address 的超集。
  4. interface 的变量可以直接赋值,但是传递的是引用