TypeScript 高级类型

本文详细介绍了TypeScript中的高级类型,包括class类、类型兼容性、交叉类型、泛型、索引签名、映射类型等。讲解了类的实例属性初始化、构造函数、实例方法、继承方式以及成员可见性。此外,还探讨了类型系统的结构化特性,以及对象、接口和函数之间的类型兼容性规则。

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

来源

概述

TS 中的高级类型有很多,重点学习以下高级类型:
  1. class 类
  2. 类型兼容性
  3. 交叉类型
  4. 泛型 和 keyof
  5. 索引签名类型 和 索引查询类型
  6. 映射类型

1. class 类

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

解释:

1. 根据 TS 中的类型推论,可以知道 Person 类的实例对象 p 的类型是 Person。
2. TS 中的 class 不仅提供了 class 的语法功能,也作为一种类型存在

实例属性初始化:

class Person {
  age: number
  gender= '男'
}
解释:
  1. 声明成员 age,类型为 number(没有初始值)。
  2. 声明成员 gender,并设置初始值,此时,可省略类型注解(TS 类型推论 为 string 类型)

 构造函数:

class Person {
  age: number
  gender: string
  constructor(age: number, gender: string) {
    this.age = age
    this.gender = gender
  }
}
解释:
  1. 成员初始化(比如,age: number)后,才可以通过 this.age 来访问实例成员。
  2. 需要为构造函数指定类型注解,否则会被隐式推断为 any;构造函数不需要返回值类型。

实例方法: 

class Point {
  x = 10
  y = 20
  scale(n: number): void {
    this.x *= n
    this.y *= n
  }
}
解释:方法的类型注解(参数和返回值)与函数用法相同。

类继承的两种方式:1 extends(继承父类) 2 implements(实现接口)。

说明:JS 中只有 extends,而 implements 是 TS 提供的。
class Animal {
  move() {
    console.log('Moving along');
  }
}

class Dog extends Animal {
  bark() {
    console.log('汪!');
  }
}

const dog = new Dog()

dog.bark()
dog.move()
解释:
  1. 通过 extends 关键字实现继承
  2. 子类 Dog 继承父类 Animal,则 Dog 的实例对象 dog 就同时具有了父类 Animal 和 子类 Dog 的所有属性和方法。
类继承的两种方式:1. extends(继承父类) 2.  implements(实现接口)
class Person implements Singable {
  sing() {
    console.log('你是我的小呀小苹果儿')
  }
}

const dog = new Person()
dog.sing()
解释:
  1. 通过 implements 关键字让 class 实现接口。
  2. Person 类实现接口 Singable 意味着,Person 类中必须提供 Singable 接口中指定的所有方法和属性

类成员可见性:可以使用 TS 来 控制 class 的方法或属性对于 class 外的代码是否可见
可见性修饰符包括:1 public(公有的) 2 protected(受保护的) 3 private(私有的)。

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

class Animal {
  public move() {
    console.log('Moving along');
  }
}
解释:
  1. 在类属性或方法前面添加 public 关键字,来修饰该属性或方法是共有的。
  2. 因为 public 是默认可见性,所以,可以直接省略

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

class Animol {
  protected move() {
    console.log('Moving along!')
  }
}
class Dog extends Animol {
  bark() {
    console.log('汪!')
    this.move()
  }
}
const bog = new Dog()
bog.bark()
解释:
  1. 在类属性或方法前面添加 protected 关键字,来修饰该属性或方法是受保护的。
  2. 在子类的方法内部可以通过 this 来访问父类中受保护的成员,但是,对实例不可见

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

class Animal {
  private move() {
    console.log('Moving along');
  }
  walk() {
    this.move()
  }
}
解释:
  1. 在类属性或方法前面添加 private 关键字,来修饰该属性或方法是私有的。
  2. 私有的属性或方法只在当前类中可见,对子类和实例对象也都是不可见的!

4. readonly: 除了可见性修饰符之外,还有一个常见修饰符就是:readonly(只读修饰符)

readonly :表示 只读 用来防止在构造函数之外对属性进行赋值
class Person {
  readonly age: number = 18
  constructor(age: number) {
    this.age = age
  }
}
解释:
  1. 使用 readonly 关键字修饰该属性是只读的,注意只能修饰属性不能修饰方法
  2. 注意:属性 age 后面的类型注解(比如,此处的 number)如果不加,则 age 的类型为 18 (字面量类型)。
  3. 接口或者 {} 表示的对象类型,也可以使用 readonly

类型兼容性

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

const p: Point = new Point2D()
解释:
  1. Point 和 Point2D 是两个名称不同的类。
  2. 变量 p 的类型被显示标注为 Point 类型,但是,它的值却是 Point2D 的实例,并且没有类型错误。
  3. 因为 TS 是结构化类型系统,只检查 Point 和 Point2D 的结构是否相同(相同,都具有 x 和 y 两个属性,属性类型也相同)。
  4. 但是,如果在 Nominal Type System 中(比如,C#、Java 等),它们是不同的类,类型无法兼容。
注意:在结构化类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型,这种说法并不准确。
更准确的说法:对于对象类型来说,y 的成员至少与 x 相同,则 x 兼容 y( 成员多的可以赋值给少的
class Point { x: number; y: number }
class Point3D { x: number; y: number; z: number }

const p: Point = new Point3D()

解释:

  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 的类型。
  •  函数之间兼容性比较复杂,需要考虑:1 参数个数 2 参数类型 3 返回值类型。

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

  

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

2.1. 参数类型,相同位置的参数类型要相同或兼容。

 解释:

  1. 注意,此处与前面讲到的接口兼容性冲突。
  2. 技巧:将对象拆开,把每个属性看做一个个参数,则,参数少的(f2)可以赋值给参数多的(f3)
  • 函数之间兼容性比较复杂,需要考虑:1 参数个数 2 参数类型 3 返回值类型。

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

解释:
  1. 如果返回值类型是原始类型,此时两个类型要相同,比如,左侧类型 F5 和 F6。
  2. 如果返回值类型是对象类型,此时成员多的可以赋值给成员少的,比如,右侧类型 F7 和 F8。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值