【TypeScript系列】类型兼容性

本文详细介绍了TypeScript中基于结构子类型的类型兼容性,探讨了接口、类、函数参数、泛型等概念的兼容规则,并提到了赋值和子类型在语言中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类型兼容性

介绍

TypeScript里的类型兼容性是基于结构子类型的。 结构类型是一种只使用其成员来描述类型的方式。 它正好与名义(nominal)类型形成对比。(译者注:在基于名义类型的类型系统中,数据类型的兼容性或等价性是通过明确的声明和/或类型的名称来决定的。这与结构性类型系统不同,它是基于类型的组成结构,且不要求明确地声明。) 看下面的例子:

interface Named {
   
    name: string;
}

class Person {
   
    name: string;
}

let p: Named;
// OK, because of structural typing
p = new Person();

在使用基于名义类型的语言,比如C#或Java中,这段代码会报错,因为Person类没有明确说明其实现了Named接口。

TypeScript的结构性子类型是根据JavaScript代码的典型写法来设计的。 因为JavaScript里广泛地使用匿名对象,例如函数表达式和对象字面量,所以使用结构类型系统来描述这些类型比使用名义类型系统更好。

关于可靠性的注意事项

TypeScript的类型系统允许某些在编译阶段无法确认其安全性的操作。当一个类型系统具此属性时,被当做是“不可靠”的。TypeScript允许这种不可靠行为的发生是经过仔细考虑的。通过这篇文章,我们会解释什么时候会发生这种情况和其有利的一面。

开始

TypeScript结构化类型系统的基本规则是,如果x要兼容y,那么y至少具有与x相同的属性。比如:

interface Named {
   
    name: string;
}

let x: Named;
// y's inferred type is { name: string; location: string; }
let y = {
    name: 'Alice', location: 'Seattle' };
x = y;

这里要检查y是否能赋值给x,编译器检查x中的每个属性,看是否能在y中也找到对应属性。 在这个例子中,y必须包含名字是namestring类型成员。y满足条件,因此赋值正确。

检查函数参数时使用相同的规则:

function greet(n: Named) {
   
    console.log('Hello, ' + n.name);
}
greet(y); // OK

注意,y有个额外的location属性,但这不会引发错误。 只有目标类型(这里是Named)的成员会被一一检查是否兼容。

这个比较过程是递归进行的,检查每个成员及子成员。

比较两个函数

相对来讲,在比较原始类型和对象类型的时候是比较容易理解的,问题是如何判断两个函数是兼容的。 下面我们从两个简单的函数入手,它们仅是参数列表略有不同:

let x = (a: number) => 0;
let y = (b: number, s: string) => 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值