TypeScript(二)

本文详细介绍了TypeScript中的关键概念,包括接口(Interface)的使用,元组(Tuple)在表示固定数量元素列表中的应用,类型推论如何简化类型注解,以及类型断言在处理特定类型转换时的作用。此外,还探讨了字面量类型、枚举(Enum)以及any类型的使用注意事项。在高级类型部分,讲解了class类的结构、继承、可见性以及类型兼容性,强调了结构化类型系统的特性。通过实例,阐述了交叉类型与接口继承的区别。

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

三、TypeScript 常用类型

8、接口

当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到复用的目的。

1. 使用 interface 关键字来声明接口。

2. 接口名称(比如,此处的 IPerson),可以是任意合法的变量名称。

3. 声明接口后,直接使用接口名称作为变量的类型。

4. 因为每一行只有一个属性类型,因此,属性类型后没有 ;(分号)。

 

interface(接口)和 type(类型别名)的对比: 相同点:都可以给对象指定类型。 不同点: 接口,只能为对象指定类型。 l 类型别名,不仅可以为对象指定类型,实际上可以为任意类型指定别名。

如果两个接口之间有相同的属性或方法,可以将公共的属性或方法抽离出来,通过继承来实现复用。

 1. 使用 extends(继承)关键字实现了接口 Point3D 继承 Point2D。

2. 继承后,Point3D 就有了 Point2D 的所有属性和方法(此时,Point3D 同时有 x、y、z 三个属性)

9、元组

场景:在地图中,使用经纬度坐标来标记位置信息。 可以使用数组来记录坐标,那么,该数组中只有两个元素,并且这两个元素都是数值类型。

使用 number[] 的缺点:不严谨,因为该类型的数组中可以出现任意多个数字。 更好的方式:元组(Tuple)。 元组类型是另一种类型的数组,它确切地知道包含多少个元素,以及特定索引对应的类型。

let position:[number,number]=[39.5427,116.2317]

1. 元组类型可以确切地标记出有多少个元素,以及每个元素的类型。

2. 该示例中,元素有两个元素,每个元素的类型都是 number。

10、类型推论

在 TS 中,某些没有明确指出类型的地方,TS 的类型推论机制会帮助提供类型。 换句话说:由于类型推论的存在,这些地方,类型注解可以省略不写! 发生类型推论的 2 种常见场景:1、 声明变量并初始化时 2、 决定函数返回值时

能省略类型注解的地方就省略(偷懒,充分利用TS类型推论的能力,提升开发效率)。

 11、类型断言

有时候你会比 TS 更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型。

 

 getElementById 方法返回值的类型是 HTMLElement,该类型只包含所有标签公共的属性或方法,不包含 a 标签特有的 href 等属性。 因此,这个类型太宽泛(不具体),无法操作 href 等 a 标签特有的属性或方法。 解决方式:这种情况下就需要使用类型断言指定更加具体的类型。

 1. 使用 as 关键字实现类型断言。

2. 关键字 as 后面的类型是一个更加具体的类型(HTMLAnchorElement 是 HTMLElement 的子类型)。

3. 通过类型断言,aLink 的类型变得更加具体,这样就可以访问 a 标签特有的属性或方法了。 另一种语法,使用 <> 语法,这种语法形式不常用知道即可: 技巧:在浏览器控制台,通过 console.dir() 打印 DOM 元素,在属性列表的最后面,即可看到该元素的类型。

 12、字面量类型

 通过 TS 类型推论机制,可以得到答案:

1. 变量 str1 的类型为:string。

2. 变量 str2 的类型为:'Hello TS'。

解释:

1. str1 是一个变量(let),它的值可以是任意字符串,所以类型为:string。

2. str2 是一个常量(const),它的值不能变化只能是 'Hello TS',所以,它的类型为:'Hello TS'。 注意:此处的 'Hello TS',就是一个字面量类型。也就是说某个特定的字符串也可以作为 TS 中的类型。 除字符串外,任意的 JS 字面量(比如,对象、数字等)都可以作为类型使用

使用模式:字面量类型配合联合类型一起使用。 使用场景:用来表示一组明确的可选值列表

比如,在贪吃蛇游戏中,游戏的方向的可选值只能是上、下、左、右中的任意一个。

 参数 direction 的值只能是 up/down/left/right 中的任意一个。 优势:相比于 string 类型,使用字面量类型更加精确、严谨。

13、枚举

枚举的功能类似于字面量类型+联合类型组合的功能,也可以表示一组明确的可选值。 枚举:定义一组命名常量。它描述一个值,该值可以是这些命名常量中的一个。

 1. 使用 enum 关键字定义枚举。

2. 约定枚举名称、枚举中的值以大写字母开头。

3. 枚举中的多个值之间通过 ,(逗号)分隔。

4. 定义好枚举后,直接使用枚举名称作为类型注解。

注意:形参 direction 的类型为枚举 Direction,那么,实参的值就应该是枚举 Direction 成员的任意一个。 访问枚举成员:

 类似于 JS 中的对象,直接通过点(.)语法访问枚举的成员。

枚举成员是有值的,默认为:从 0 开始自增的数值。 我们把,枚举成员的值为数字的枚举,称为:数字枚举。 当然,也可以给枚举中的成员初始化值。

 字符串枚举:枚举成员的值是字符串。字符串枚举没有自增长行为,因此,字符串枚举的每个成员必须有初始值。

枚举是 TS 为数不多的非 JavaScript 类型级扩展(不仅仅是类型)的特性之一。 因为:其他类型仅仅被当做类型,而枚举不仅用作类型,还提供值(枚举成员都是有值的)。 也就是说,其他的类型会在编译为 JS 代码时自动移除。但是,枚举类型会被编译为 JS 代码!

枚举与前面讲到的字面量类型+联合类型组合的功能类似,都用来表示一组明确的可选值列表。 一般情况下,推荐使用字面量类型+联合类型组合的方式,因为相比枚举,这种方式更加直观、简洁、高效。

14、any类型

原则:不推荐使用 any!这会让 TypeScript 变为 “AnyScript”(失去 TS 类型保护的优势)。 因为当值的类型为 any 时,可以对该值进行任意操作,并且不会有代码提示。

 以上操作都不会有任何类型错误提示,即使可能存在错误! 尽可能的避免使用 any 类型,除非临时使用 any 来“避免”书写很长、很复杂的类型! 其他隐式具有 any 类型的情况:1 声明变量不提供类型也不提供默认值 2 函数参数不加类型。 注意:因为不推荐使用 any,所以,这两种情况下都应该提供类型!

15、typeof

众所周知,JS 中提供了 typeof 操作符,用来在 JS 中获取数据的类型。

实际上,TS 也提供了 typeof 操作符:可以在类型上下文中引用变量或属性的类型(类型查询)。 使用场景:根据已有变量的值,获取该值的类型,来简化类型书写。

 1. 使用 typeof 操作符来获取变量 p 的类型,结果与第一种(对象字面量形式的类型)相同。

2. typeof 出现在类型注解的位置(参数名称的冒号后面)所处的环境就在类型上下文(区别于 JS 代码)。

3. 注意:typeof 只能用来查询变量或属性的类型,无法查询其他形式的类型(比如,函数调用的类型)。

四、TypeScript高级类型

1、class类

TypeScript 全面支持 ES2015 中引入的 class 关键字,并为其添加了类型注解和其他语法(比如,可见性修饰符等)。

class Person{}

const p=new person()

1. 根据 TS 中的类型推论,可以知道 Person 类的实例对象 p 的类型是 Person。

2. TS 中的 class,不仅提供了 class 的语法功能,也作为一种类型存在。

实例初始化

 1. 声明成员 age,类型为 number(没有初始值)。

2. 声明成员 gender,并设置初始值,此时,可省略类型注解(TS 类型推论 为 string 类型)。

构造函数:

 1. 成员初始化(比如,age: number)后,才可以通过 this.age 来访问实例成员。

2. 需要为构造函数指定类型注解,否则会被隐式推断为 any;构造函数不需要返回值类型。

实例方法:

 方法的类型注解(参数和返回值)与函数用法相同。

继承:

类继承的两种方式:1 extends(继承父类) 2 implements(实现接口)。 说明:JS 中只有 extends,而 implements 是 TS 提供的。

 1. 通过 extends 关键字实现继承。

2. 子类 Dog 继承父类 Animal,则 Dog 的实例对象 dog 就同时具有了父类 Animal 和 子类 Dog 的所有属性和方法。

 1. 通过 implements 关键字让 class 实现接口。

2. Person 类实现接口 Singable 意味着,Person 类中必须提供 Singable 接口中指定的所有方法和属性。

类成员可见性:可以使用 TS 来控制 class 的方法或属性对于 class 外的代码是否可见。

可见性修饰符包括:1 public(公有的) 2 protected(受保护的) 3 private(私有的)。

 public:表示公有的、公开的,公有成员可以被任何地方访问,默认可见性。

 1. 在类属性或方法前面添加 public 关键字,来修饰该属性或方法是共有的。

2. 因为 public 是默认可见性,所以,可以直接省略。

protected:表示受保护的,仅对其声明所在类和子类中(非实例对象)可见。

1. 在类属性或方法前面添加 protected 关键字,来修饰该属性或方法是受保护的。

2. 在子类的方法内部可以通过 this 来访问父类中受保护的成员,但是,对实例不可见!

private:表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的。

 1. 在类属性或方法前面添加 private 关键字,来修饰该属性或方法是私有的。

2. 私有的属性或方法只在当前类中可见,对子类和实例对象也都是不可见的!

readonly:表示只读,用来防止在构造函数之外对属性进行赋值。

 1. 使用 readonly 关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法。

2. 注意:属性 age 后面的类型注解(比如,此处的 number)如果不加,则 age 的类型为 18 (字面量类型)。

3. 接口或者 {} 表示的对象类型,也可以使用 readonly。

2、类型兼容性

两种类型系统:1 Structural Type System(结构化类型系统) 2 Nominal Type System(标明类型系统)。 TS 采用的是结构化类型系统,也叫做 duck typing(鸭子类型),类型检查关注的是值所具有的形状。 也就是说,在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型

 1. Point 和 Point2D 是两个名称不同的类。

2. 变量 p 的类型被显示标注为 Point 类型,但是,它的值却是 Point2D 的实例,并且没有类型错误。

3. 因为 TS 是结构化类型系统,只检查 Point 和 Point2D 的结构是否相同(相同,都具有 x 和 y 两个属性,属性类型也相同)。

4. 但是,如果在 Nominal Type System 中(比如,C#、Java 等),它们是不同的类,类型无法兼容。

注意:在结构化类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型,这种说法并不准确。 更准确的说法:对于对象类型来说,y 的成员至少与 x 相同,则 x 兼容 y(成员多的可以赋值给少的)。

 1. Point3D 的成员至少与 Point 相同,则 Point 兼容 Point3D。

2. 所以,成员多的 Point3D 可以赋值给成员少的 Point。

除了 class 之外,TS 中的其他类型也存在相互兼容的情况,包括:1 接口兼容性 2 函数兼容性 等。接口之间的兼容性,类似于 class。并且,class 和 interface 之间也可以兼容。

 函数之间兼容性比较复杂,需要考虑:1 参数个数 2 参数类型 3 返回值类型。

1. 参数个数,参数多的兼容参数少的(或者说,参数少的可以赋值给多的)。

 1. 参数少的可以赋值给参数多的,所以,f1 可以赋值给 f2。

2. 数组 forEach 方法的第一个参数是回调函数,该示例中类型为:(value: string, index: number, array: string[]) => void。

3. 在 JS 中省略用不到的函数参数实际上是很常见的,这样的使用方式,促成了 TS 中函数类型之间的兼容性。

4. 并且因为回调函数是有类型的,所以,TS 会自动推导出参数 item、index、array 的类型。

2. 参数类型,相同位置的参数类型要相同(原始类型)或兼容(对象类型)。

 函数类型 F2 兼容函数类型 F1,因为 F1 和 F2 的第一个参数类型相同。

1. 注意,此处与前面讲到的接口兼容性冲突。

2. 技巧:将对象拆开,把每个属性看做一个个参数,则,参数少的(f2)可以赋值给参数多的(f3)。

3. 返回值类型,只关注返回值类型本身即可:

 1. 如果返回值类型是原始类型,此时两个类型要相同,比如,左侧类型 F5 和 F6。

2. 如果返回值类型是对象类型,此时成员多的可以赋值给成员少的,比如,右侧类型 F7 和 F8。

3、交叉类型

交叉类型(&)和接口继承(extends)的对比:

相同点:都可以实现对象类型的组合。

 不同点:两种方式实现类型组合时,对于同名属性之间,处理类型冲突的方式不同。

 

 以上代码,接口继承会报错(类型不兼容);交叉类型没有错误,可以简单的理解为:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值