在大多数情况下,我们在使用对象前就可以确定对象的结构,并为对象中的属性添加准确的类型。
但是当我们无法确定对象中有哪些属性时,或者说对象中可以出现任意多个属性时,此时,我们就可以用索引签名类型了。
⏰
索引签名
,主要是用来规定索引和属性值的类型,索引类型只能是
string
类型 或者
number
类型 或者
symbol
类型。
🔔 在 TypeScript 中,索引签名类型包括
字符串索引签名类型
和
数字索引签名类型
。
二、字符串索引签名类型
1. 语法格式
interface MyObj {
[key: string]: number;
上面的这段代码中,使用 [key: string] 来约束该接口中允许出现的属性名称,其中 key 表示字符串索引的标识符,可以是任何有效的属性名,而 number 表示对应属性的值的类型,可以是任意类型。
2. 用法
interface MyObj {
[key: string]: number;
let obj: MyObj = {
a: 1,
b: 2,
c: 3,
如果对象中属性值的类型不是 number 类型,代码会报错。
interface MyObj {
[key: string]: number;
let obj: MyObj = {
a: 1, // 🙆:正确
b: 2, // 🙆:正确
name: "Echo", // 🙅报错:不能将类型“string”分配给类型“number”
bool: true, // 🙅报错:不能将类型“boolean”分配给类型“number”
3. 特点
一旦定义了索引签名,那么必选属性和可选属性的类型都必须是它的类型的子集。
返回的属性值的类型必须是索引签名指定的类型。
可以与其他明确声明的属性共存。
可以同时拥有多种类型的索引签名。
// Ok
interface Person {
// 同时拥有 string 类型和 number 类型的索引签名
[props: string]: string | number;
// 可以定义其它属性,但是属性值的类型必须是索引签名类型的子集
// 这里的属性值类型必须是 string 类型或者 number 类型
name: string;
age: number;
// Error
interface User1 {
[prop: string]: string | number;
// 🙅报错:类型“string | undefined”的属性“name”不能赋给“string”索引类型“string | number”。
// ‘name’的属性值类型虽然为’string‘是‘string | number’的子集,但是当其为可选时,值类型就变为‘string | undefined 类型。
name?: string,
age: number
// Error
interface User {
[props: string]: string | number;
name: string;
age: number;
// 🙅报错:类型“true”的属性“bool”不能赋给“string”索引类型“string | number”。
// 由于上面的索引签名规定了只能是 string 类型或者 number 类型,所以这里不能写其它类型
bool: true;
console.log(person.name); // 输出:Echo
console.log(person["age"]); // 输出:26
console.log(person.city); // 输出:GuangZhou
console.log(person["phone"]); // 输出:13000000000
console.log(person["gender"]); // 输出:Male
//访问不存在的属性
console.log(person["address"]); // 输出:undefined
三、数字索引签名类型
当一个对象具有数字索引签名时,它意味着该对象可以使用数字来索引并获得相应的属性的值。
1. 语法
interface MyArr {
[index: number]: string
上面的这段代码中,我们定义了 MyArr 接口,它具有索引签名。这个索引签名表示了当用 number 去索引 MyArr 时会得到 string 类型的返回值。
2. 用法格式
interface MyArr {
[index: number]: string;
const arr: MyArr = ["Echo", "James", "John", "Steven"];
console.log(arr[0]); // Echo
console.log(arr[1]); // James
console.log(arr[2]); // John
console.log(arr[3]); // Steven
3. 特点
可以同时拥有多种类型的索引签名。
返回的属性值的类型必须是索引签名指定的类型。
interface MyArr {
[index: number]: string | number;
const arr: MyArr = [1, 'a', 2, 'b'];
四、注意事项
1、索引签名的键只能是 string、number、symbol 或者模板文本类型
interface MyObj {
//🙅报错:索引签名参数类型必须是 “string”、“number”、“symbol”或模板文本类型。
//这里参数类型为boolean类型了
[key: boolean]: boolean;
2. 不能多次定义相同类型的索引签名
interface MyObj {
//🙅报错: 类型“string”的索引签名重复。
[key: string]: string;
[key: string]: number;
五、索引签名类型 VS 泛型工具类型Record<K, T>
先看看下面的代码,我们发现索引签名类型和泛型工具类型 Record<K, T> 很相似:
const object1: Record<string, string> = { name: "Echo" }; // 正确
const object2: { [key: string]: string } = { name: "Echo" }; // 正确
但实际上它们两者之间还是有区别的:
1. 用途不同
索引签名类型:主要用于定义具有动态属性的对象,允许通过字符串或数字索引来访问属性。
interface MyObj {
[key: string]: string | number
const obj: MyObj = {
name: "Echo",
age: 26
console.log(obj.name); // Echo
console.log(obj["age"]); // 26
type NewPerson = Record<keyof Person, string>;
const person: NewPerson = {
name: "Echo",
gender: "Male",
2. 类型约束
索引签名类型:对于索引签名,键的类型可以是 string、number、symbol 或者模板文本类型,值的类型可以是任意类型。
interface MyObj {
//🙅报错:索引签名参数类型必须是 “string”、“number”、“symbol”或模板文本类型。
//这里参数类型为boolean类型了
[key: boolean]: boolean;
Record<K, T>:对于 Record<K, T>,类型参数 K 的类型可以是 string、number 或 symbol,可以接收字面量类型或者字面量类型组成的联合类型来作为参数,而类型参数 T 可以是任意类型。
比如使用联合类型来作为 Key 值:
type Person = Record<"name" | "age" | "gender" | "bool", string | number | boolean>;
const person: Person = {
name: "Echo",
age: 26,
gender: "Male",
bool: true,