前言

目标


高级类型 1 class类 1111

1 class类

TS中的class,不仅提供了class语法,也作为一种类型存在
【TS】3 高级类型_类型

1.1 实例属性

给class添加实例成员
【TS】3 高级类型_泛型_02

1.2 构造函数

构造函数语法规则:

  • 成员初始化(比如,age:number)后,才可以通过this.age来访问实例成员
  • 需要为构造函数指定类型注解,否则会被隐式推断为any;
  • 构造函数不需要返回值类型
class person {
    age:number
    sex = '男'
    constructor(age:number,sex:string){
        this.age = age
        this.sex = sex
    }
}
const p = new person(18,'男')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

1.3 实例方法

实例方法的类型注解(参数与返回值)与函数的相同
【TS】3 高级类型_类型_03

1.4 类的继承

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

1.4.1 extends

类Dog继承类Animal之后,实例化类Dog就可以调用类Animal中的方法或属性
【TS】3 高级类型_类型_04

1.4.2 implements

implements实现继承

  • 通过 implements 关键字让class 实现接口 Person 类实现接口Singable
  • Person 类实现接口Singable意味着,Person类中必须提供Singable 接口中指定的所有方法和属性
interface Singgle{
    name:string
    sing():void
}

class person implements Singgle {
    name: string
    sing(){
        console.log('我是歌手')
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

1.5 可见性修饰符

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

  1. public (公有的) —— 默认
  2. protected (受保护的)
  3. private (私有的)。
1.5.1 public可见的

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

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

class Point {
    x=1
    public y=2
    public scale(n:number){
        this.x *= n
        this.y *= n
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
1.5.2 protected受保护的

protected: 表示受保护的,仅对其声明所在类和子类中(非实例对象)可见
【TS】3 高级类型_泛型_05

1.5.3 private私有的

private: 表示私有的,只在当前类中可见,对实例对象以及子类也是不可见的。
【TS】3 高级类型_类型_06

1.6 readonly只读修饰符

readonly: 只能修饰属性,不能修饰方法

  • 在class类中使用,表示只读,用来防止在构造函数之外属性进行赋值
  • 在接口或{}对象中,表示属性只读
    【TS】3 高级类型_泛型_07

对象或接口只读属性,不可修改
【TS】3 高级类型_泛型_08

2 类型兼容性

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

‘’【TS】3 高级类型_类型_09
Point与Ponint2D是两个不同名称的类,但是内部结构一样
变量p的类型被显示标注为Point类型,但是,它的值却是Point2D 的实例,并且没有类型错误。
因为TS是结构化类型系统,只检查Point和 Point2D 的结构是否相同(相同,都具有X和两个属性,属性类型也相同)

2.1 对象兼容性

成员多的可以赋值给成员少的
【TS】3 高级类型_泛型_10

2.2 接口兼容性

接口之间的兼容性类似于class,且,class与interface接口之间也可以兼容
1 相同位置的参数类型要相同或者兼容
2 成员多的可以赋值给成员少的
【TS】3 高级类型_类型_11

2.3 函数兼容性

函数兼容性要考虑以下三个方面: 1 参数个数 2参数类型 3返回值类型
1 参数个数
参数少的可以赋值给参数多的
参数少的f1可以赋值给参数多的f2
【TS】3 高级类型_类型_12
2 参数类型
相同位置的参数类型要相同或者兼容
【TS】3 高级类型_泛型_13
将定义的参数类型拆开参数少的可以赋值给参数多的
【TS】3 高级类型_类型_14
3 返回值类型
我们只需要关注返回值本身即可

若返回值是原始类型,此时返回值类型相同即可,例如F1和F2
若返回值是对象类型,此时成员多的可以赋值给成员少的,例如F3和F4
【TS】3 高级类型_泛型_15

3 交叉类型

交叉类型(&):功能类似接口继承(extends),用于组合多个类型为一个类型(常用于对象类型)

A与B交叉之后形成的C,有A与B中的属性
【TS】3 高级类型_泛型_16

交叉类型与接口继承的区别

相同点:都可实现对象类型组合
不同点:对同名属性,处理冲突的方式不同
1 接口继承 - 同名属性
同名属性类型不同,使用接口继承会报错
【TS】3 高级类型_泛型_17
2 交叉类型 - 同名属性

使用交叉类型,函数中参数冲突,会取两个类型
【TS】3 高级类型_类型_18
对象中的同名属性类型不同,会导致交叉报错
【TS】3 高级类型_泛型_19

4 泛型和keyof

4.1 泛型的创建与使用

泛型是可以在保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用,常用于: 函数接口class
创建一个泛型
类型变量Type - 任意合法的变量名称,是一种特殊类型的变量,它处理类型而不是值。相当于一个类型容器,能够捕获用户提供的类型(具体类型由用户调用时指定)

// 创建一个泛型函数
function genericity<Type>(value:Type):Type  {
    return value
}
  • 1.
  • 2.
  • 3.
  • 4.

使用泛型函数

推荐使用简化方式调用泛型函数
当编译器无法推断类型或者推断的类型不准确时,就需要显式地传入类型参数。

// 使用泛型
let num:number = genericity<number>(1)
let str:string = genericity<string>('1')

// 使用泛型 - 简写
let num1:number = genericity(1)
let str1:string = genericity('1')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

4.2 泛型的约束

泛型约束:默认情况下,泛型函数的类型变量Type可以代表多个类型,这导致无法访问任何属性。
例如:想获取参数长度,无法保证所有的Type类型都有length,number类型无length长度
【TS】3 高级类型_泛型_20
1 指定更加具体的类型
指定取值和返回值类型为数组类型
【TS】3 高级类型_泛型_21
2 添加约束
创建描述约束的接口ILength,该接口要求提供length属性
extends为该泛型添加约束
Type extends ILength 传入的Type类型要有length属性,即数组、字符串等
【TS】3 高级类型_泛型_22

4.3 多个泛型变量

泛型的类型变量可以有多个,并且类型变量之间还可以约束。

创建一个函数,获取对象中属性的值
key只能是Type所有键中的任何一个

function genericity<Type,Key extends keyof Type>(obj:Type,key:Key) {
    return obj[key]
}
  • 1.
  • 2.
  • 3.

传入的是对象,key可以是对象的属性
【TS】3 高级类型_类型_23
传入的是数组,key可以是数组的下标或者数组相关的方法等属性
【TS】3 高级类型_类型_24

4.4 泛型接口

泛型接口: 接口也可以配合泛型来使用,以增加其灵活性,增强其复用性

8创建泛型接口*
接口的类型变量Type,接口中的所有成员都可以使用

interface idFun<Type>{
    id:(value:Type)=>Type
    name:()=>Type[]
}
  • 1.
  • 2.
  • 3.
  • 4.

使用泛型接口
需要显示的指定具体的类型,idFun< number >

let obj:idFun<number> = {
    id:value=>value,  // 返回类型是number
    name:()=>[1,2,3]  // 返回类型是numbers[]
}
  • 1.
  • 2.
  • 3.
  • 4.

扩展: 在TS中数组其实是一个泛型接口
定于一个数组,查看一下数组的提示Array< number > 类似于接口名<类型变量>
根据提示看一下Array数组的源码 【TS】3 高级类型_类型_25
在TS的找到了Array的接口源码,< T > 等同于< Type >,forEach在Array接口中的一个属性
【TS】3 高级类型_泛型_26
【TS】3 高级类型_泛型_27

4.5 泛型类

创建泛型类

class genericity<numType>{
    defalueValue:numType
    add:(x:numType,y:numType)=> numType
    // constructor(value:numType){
    //     this.defalueValue = value
    // }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

使用泛型类

// 完整写法
let g = new genericity<number>()
g.defalueValue = 1

// 简写 —— 类中有constructor且使用类型变量,则类型变量可以省略
let g1 = new genericity(100)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

4.6 泛型工具类型

泛型工具类型: TS内置了一些常用的工具类型,来简化TS 中的一些常见操作。
说明:它们都是基于泛型实现的(泛型适用于多种类型,更加通用),并且是内置的,可以直接在代码中使用这些工具类型有很多,常用的有以下四个

  1. Partial< Type>
  2. Readonly< Type>
  3. Pick<Type,keys>
  4. Record<Keys,Type>
4.6.1 Partial< Type >

Partial< Type > 用来构造(创建)一个类型,将Type的所有属性设为可选
【TS】3 高级类型_泛型_28

4.6.2 Readonly< Type >

Readonly< Type > 用来构造一个类型,将Type 的所有属性都设置为 readonly (只读)
【TS】3 高级类型_泛型_29

4.6.3 Pick<Type,keys>

Pick<Type,Keys> 从 Type 中选择一组属性来构造新类型

Type 要选择谁的属性,Keys选择那几个属性(只能是Type属性中存在的属性
【TS】3 高级类型_类型_30

4.6.4 Record<Type,keys>

Record<Keys,Type> 构造一个对象类型,属性键为Keys,属性类型为Type

keys作为属性名,Type作为属性类型,构造一个对象类型
【TS】3 高级类型_类型_31

5 索引签名类型和索引查询类型

索引类型签名:当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性),此时,就用到索引签名类型了。

5.1 对象索引签名类型

创建一个索引对象类型

// 对象类型
interface obj<Type>{
    [key:string]:Type
}
  • 1.
  • 2.
  • 3.
  • 4.

使用
可以根据需要向obj1中添加多个属性,变量属性必传

let obj1:obj<number> = {
    name:1,
    age:2,
    a:222
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

5.2 数组索引签名类型

数组类型

interface Arr<Type>{
    [index:number]:Type
}
  • 1.
  • 2.
  • 3.

使用

let arr:Arr<string> = ['1','2','3']
  • 1.

5.3 索引查询

基本查询

查询方式类似于JS中的对象查询:obj[key]
【TS】3 高级类型_泛型_32

多个查询

查询多个

proKeys[‘a’|‘b’]

【TS】3 高级类型_类型_33
查询所有

proKeys[keyof proKeys]

【TS】3 高级类型_类型_34

6 映射类型

映射类型: 基于旧类型创建新类型(对象类型),减少重复、提升开发效率,基于签名索引类型

6.1 映射类型使用

1 in 创建

type ProKeys = 'name'|'age'
type ob = {name:string,age:string}
  • 1.
  • 2.

根据以上代码 用映射类型简化ob的定义,obj1 与ob结构完全相同

// 映射类型
type obj1 = {[key in ProKeys]:string}
let obj:obj1 = { 
    name:'张三',
    age:'18'
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

映射类型是能在类型别名type中使用,不能在接口中使用
【TS】3 高级类型_类型_35
2 keyof 根据对象类型创建

type proKeys = {a:string,b:string,c:string}
// 根据映射类型创建
type obj = {[key in keyof proKeys]:string}

// 使用联合类型
let obj1:obj = {
    a:'1',
    b:'2',
    c:'3'
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

6.2 基于映射类型实现的泛型工具Partial< Type>

先来看一下 Partial< Type >的作用: 用来构造(创建)一个类型,将Type的所有属性设为可选

ts源码中有关Partial的定义,[P in keyof T] 使用的是映射类型
T - 对象
P - 键名
T[P] - 键名对应的类型
【TS】3 高级类型_泛型_36
根据Partial源码成创建一个Partial1实现 Partial一样的效果,可以看到使用之后可以实现一样的可选效果
【TS】3 高级类型_类型_37