LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

typescript结构化类型应用两例

freeflydom
2025年7月7日 8:28 本文热度 92

第一个例子

下面的代码定义了一个Person类型

interface Person {
  name: string;
  age: number;
}

然后又定义了一个函数打印这个类型的对象

function printPerson(person: Person) {
  console.log(`Name: ${person.name}, Age: ${person.age}`);
}

按道理来说,要调用这个函数,必须传递一个Person类型的对象,但是你会发现,直接传一个对象进去也行。

printPerson({ name: "Alice", age: 30 });

这段代码没有报错,为什么呢?因为typescript的结构化类型系统认为,只要传入的对象包含了Person类型所需的所有属性,就可以被认为是Person类型。你甚至可以多加一些属性,比如:

printPerson({ name: "Alice", age: 30, location: "Wonderland" });

代码一样可以正常运行!

为什么?因为在typescript中,类型是基于结构的,而不是基于名称的。只要对象的结构符合要求,就可以被认为是该类型。如果一个类型A包含了类型B的所有属性,那么类型A就可以被认为是类型B。在使用类型B的地方,就可以使用类型A代替。

第二个例子

还是以上面的Person类型为例,假设我们要打印Person对象中的所有属性,有的同学可能不假思索的写下如下代码:

interface Person {
  name: string;
  age: number;
}
const person: Person = { name: "Alice", age: 30 };
function printProperties(person: Person) {
  for (const property in person) {
    console.log(`${property}: ${person[property]}`);
  }
}
printProperties(person);

但是这段代码却报错了:

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Person'. No index signature with a parameter of type 'string' was found on type 'Person'.

当我第一次看到这个错误时,我只想撞墙,我哪里用any了,这不是胡扯吗?但这不是对待错误的正确态度,这种错误如果不彻底解决,那么它就会一直困扰你,只有将它彻底击败,下次再遇到时才能得心应手!

仔细看一下这个报错,它大概描述了两件事情:

  1. string类型的值不能用来索引Person类型。
  2. Person类型没有定义索引签名。

其实这两件事本质上说的是一个问题,那就是在TypeScript中,只有在类型中显式定义了索引签名,才能使用string类型的值来索引该类型。那么我们就给Person类型添加一个索引签名:

方式一:为Person类型添加索引签名

interface Person {
  name: string;
  age: number;
  [key: string]: any; // 索引签名
}

[key: string]: any; 这行代码的意思是,Person类型可以有任意数量的属性,属性名必须是字符串类型 ([key: string]),属性值可以是任意类型(any)。

现在我们再来运行printProperties函数,就不会报错了。

方式二:使用keyof关键字

坦白的说,为了一个遍历函数给Person类型添加一个索引签名有点过于冗余了,其实我们可以使用另一个方法来解决这个问题,那就是使用keyof关键字来获取Person类型的所有属性名。

function printProperties(person: Person) {
  for (const property in person) {
    console.log(`${property}: ${person[property as keyof typeof person]}`);
  }
}

来看这一句代码property as keyof typeof person, 它的执行步骤是这样的:

  1. 先执行typeof person,得到Person类型。
  2. 再执行keyof Person,得到Person类型的所有属性名的联合类型 - name | age
  3. 最后使用as操作符将property转换为这个联合类型。

这样做的好处是,property的类型被限制为Person类型的属性名,在本例中就是nameage这两个属性,绝不会超出这个范围,这样就可以安全地索引person对象了。

眼力好的同学可能已经发现了,上面这个写法可以简化一下,property as keyof typeof person可以简化为property as keyof Person,因为person的类型就是Person,所以我们可以直接使用Person类型来代替。这样可以节省一个typeof操作符的使用。

方式三:使用Object.entries

当然,我们还可以使用Object.entries方法来遍历对象的属性,这样就不需要担心索引签名的问题了。

function printProperty(person: Person) {
  Object.entries(person).forEach(([key, value]) => {
    console.log(`${key}: ${value}`);
  });
}

分析一下这段代码:

  1. Object.entries方法会返回一个二维数组,其中每个元素又是一个数组,这个数组包含了对象的属性名和属性值。以上面的person对象为例,Object.entries(person)会返回[['name', 'Alice'], ['age', 30]]
  2. 接下来的forEach方法会遍历这个数组,这里使用了一个数组解构操作符([key, value]),将每个属性的名字赋值给key,属性的值赋值给value,
  3. 最后使用console.log打印出来。

​转自https://www.cnblogs.com/graphics/p/18968833


该文章在 2025/7/7 8:28:05 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved