深入理解TypeScript 类型兼容性

 更新时间:2024年01月17日 15:06:55   作者:前端玖耀里  
本文主要介绍了TypeScript 在函数、枚举、类和泛型中的类型兼容性规则,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

我们学习类型兼容性,就是在学习 TypeScript 在一个类型能否赋值给其他类型的规则。本节将会详细介绍 TypeScript 在函数、枚举、类和泛型中的类型兼容性规则。

1. 解释

类型兼容性用于确定一个类型是否能赋值给其他类型。

TypeScript 的类型检查机制都是为了让开发者在编译阶段就可以直观的发现代码书写问题,养成良好的代码规范从而避免很多低级错误。

let address: string = 'Baker Street 221B'
let year: number = 2010
address = year // Error

代码解释: 第 3 行,类型 ‘number’ 不能赋值给类型 ‘string’。

2. 结构化

TypeScript 类型兼容性是基于结构类型的;结构类型只使用其成员来描述类型。

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

interface User {
  name: string,
  year: number
}

let protagonist = {
  name: 'Sherlock·Holmes',
  year: 1854,
  address: 'Baker Street 221B'
}

let user: User = protagonist // OK

代码解释: 接口 User 中的每一个属性在 protagonist 对象中都能找到对应的属性,且类型匹配。另外,可以看到 protagonist 具有一个额外的属性 address,但是赋值同样会成功。

3. 比较两个函数

相对来讲,在比较原始类型和对象类型的时候是比较容易理解的,难的是如何判断两个函数是否兼容。判断两个函数是否兼容,首先要看参数是否兼容,第二个还要看返回值是否兼容。

3.1 函数参数

先看一段代码示例:

let fn1 = (a: number, b: string) => {}
let fn2 = (c: number, d: string, e: boolean) => {}

fn2 = fn1 // OK
fn1 = fn2 // Error

代码解释:

第 4 行,将 fn1 赋值给 fn2 成立是因为:

  • fn1 的每个参数均能在 fn2 中找到对应类型的参数
  • 参数顺序保持一致,参数类型对应
  • 参数名称不需要相同

第 5 行,将 fn2 赋值给 fn1 不成立,是因为 fn2 中的必须参数必须在 fn1 中找到对应的参数,显然第三个布尔类型的参数在 fn1 中未找到。

参数类型对应即可,不需要完全相同:

let fn1 = (a: number | string, b: string) => {}
let fn2 = (c: number, d: string, e: boolean) => {}

fn2 = fn1 // OK

代码解释: fn1 的第一个参数是 number 和 string 的联合类型,可以对应 fn2 的第一个参数类型 number,所以第 4 行赋值正常。

3.2 函数返回值

创建两个仅是返回值类型不同的函数

代码解释: 最后一行,函数 x() 缺少 location 属性,所以报错。

类型系统强制源函数的返回值类型必须是目标函数返回值类型的子类型。由此可以得出如果目标函数的返回值类型是 void,那么源函数返回值可以是任意类型:

let x : () => void
let y = () => 'mybj'

x = y // OK

4. 枚举的类型兼容性

枚举与数字类型相互兼容:

enum Status {
  Pending,
  Resolved,
  Rejected
}

let current = Status.Pending
let num = 0

current = num
num = current

不同枚举类型之间是不兼容的:

enum Status { Pending, Resolved, Rejected }
enum Color { Red, Blue, Green }

let current = Status.Pending
current = Color.Red // Error

5. 类的类型兼容性

类与对象字面量和接口的兼容性非常类似,但是类分实例部分和静态部分。

比较两个类类型数据时,只有实例成员会被比较,静态成员和构造函数不会比较。

class Animal {
  feet!: number
  constructor(name: string, numFeet: number) { }
}

class Size {
  feet!: number
  constructor(numFeet: number) { }
}

let a: Animal
let s: Size

a = s!  // OK
s = a  // OK

代码解释: 类 Animal 和类 Size 有相同的实例成员 feat 属性,且类型相同,构造函数参数虽然不同,但构造函数不参与两个类类型比较,所以最后两行可以相互赋值。

类的私有成员和受保护成员会影响兼容性。 允许子类赋值给父类,但是不能赋值给其它有同样类型的类。

class Animal {
  protected feet!: number
  constructor(name: string, numFeet: number) { }
}

class Dog extends Animal {}

let a: Animal
let d: Dog

a = d! // OK
d = a // OK

class Size {
  feet!: number
  constructor(numFeet: number) { }
}

let s: Size

a = s! // Error

代码解释:

第 13 行,子类可以赋值给父类。

第 14 行,父类之所以能够给赋值给子类,是因为子类中没有成员。

最后一行,因为类 Animal 中的成员 feet 是受保护的,所以不能赋值成功。

6. 泛型的类型兼容性

泛型的类型兼容性根据其是否被成员使用而不同。先看一段代码示例:

interface Empty<T> {}

let x: Empty<number>
let y: Empty<string>

x = y! // OK

上面代码里,x 和 y 是兼容的,因为它们的结构使用类型参数时并没有什么不同。但是当泛型被成员使用时:

interface NotEmpty<T> {
  data: T
}
let x: NotEmpty<number>
let y: NotEmpty<string>

x = y! // Error

代码解释: 因为第 4 行,泛型参数是 number 类型,第 5 行,泛型参数是 string 类型,所以最后一行赋值失败。

如果没有指定泛型类型的泛型参数,会把所有泛型参数当成 any 类型比较

7. 小结

要充分利用 TypeScript 的类型检查机制规范代码,减少一些不必要的错误,这也是我们使用 TypeScript 的初衷。

到此这篇关于深入理解TypeScript 类型兼容性的文章就介绍到这了,更多相关TypeScript类型兼容性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:

相关文章

  • uniapp 仿微信的右边下拉选择弹出框的实现代码

    uniapp 仿微信的右边下拉选择弹出框的实现代码

    这篇文章主要介绍了uniapp 仿微信的右边下拉选择弹出框的实现代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • 发现的以前不知道的函数

    发现的以前不知道的函数

    发现的以前不知道的函数...
    2006-09-09
  • 原生JavaScript实现轮播图效果

    原生JavaScript实现轮播图效果

    这篇文章主要为大家详细介绍了原生JavaScript实现轮播图效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • 没有document.getElementByName方法

    没有document.getElementByName方法

    document.getElementByName方法没有document.getElementsByName得到的是标签的数组,下面为大家详细介绍下具体的使用,感兴趣的朋友可以参考下,希望对大家有所帮助
    2013-08-08
  • js中的cookie的读写操作示例详解

    js中的cookie的读写操作示例详解

    cookie是有有效期的,cookie的默认有效期是从cookie生成至浏览器关闭,也可以通过设置cookie的有效期来指定其失效日期;用户也可以禁止cookie也可以手动删除cookie
    2014-04-04
  • 使弱类型的语言JavaScript变强势

    使弱类型的语言JavaScript变强势

    Javascript (ECMA Script)是一种弱类型的语言.这并不意味着它没有数据类型,只是变量或者Javascript对象属性不需要一个特定类型的值分配给它或者它始终使用相同的值.Javascript中的变量同样支持自由类型转换成为适用(或者要求)的内容以便于使用.
    2009-06-06
  • js实现对table动态添加、删除和更新的方法

    js实现对table动态添加、删除和更新的方法

    这篇文章主要介绍了js实现对table动态添加、删除和更新的方法,涉及javascript针对html中table表格节点的操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • 关于JavaScript数组你所不知道的3件事

    关于JavaScript数组你所不知道的3件事

    这篇文章主要为大家详细介绍了关于JavaScript数组三个并不那么常见的功能,你所不知道的事情,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • javascript设计模式之解释器模式详解

    javascript设计模式之解释器模式详解

    这篇文章主要介绍了javascript设计模式之解释器模式详解,当有一个语言需要解释执行,并且可以将该语言中的句子表示为一个抽象语法树的时候,可以考虑使用解释器模式,需要的朋友可以参考下
    2014-06-06
  • js仿土豆网带缩略图的焦点图片切换效果实现方法

    js仿土豆网带缩略图的焦点图片切换效果实现方法

    这篇文章主要介绍了js仿土豆网带缩略图的焦点图片切换效果实现方法,涉及javascript操作图片特效的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02

最新评论