TypeScript

2023/2/16 TS

# TypeScript简述

  • 以JavaScript为基础构建的语言。
  • 是JavaScript的超集。
  • 可以在任何支持JavaScript的平台中执行。
  • TypeScript扩展了JavaScript,并添加了类型 TypeScript的增加

# TypeScript开发环境搭建

  • 下载Node.js。
  • 使用npm全局安装typescript:npm i -g typescript
  • 创建ts文件。
  • 使用tsc对ts文件进行编译。
    • 使用命令行进入ts文件所在目录。
    • 执行命令:tsc xxx.ts

# 基本类型

# 类型声明

  • 类型声明是TS最重要的特点之一。
  • 通过类型声明可以指定TS中变量(参数、形参)的类型。
  • 指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值、否则报错。
  • 语法:
let 变量: 类型;

let 变量: 类型 =;

function fn(参数: 类型, 参数: 类型): 类型 {
  ...
}
1
2
3
4
5
6
7

# 自动类型判断

  • TS又有自动的类型判断机制
  • 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型。
  • 故当变量的声明和赋值是同时进行时,可以省略类型声明。

# 类型

类型

  • number
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;
1
2
3
4
5
  • boolean
let isDone: boolean = false;
1
  • string
let color: string = "blue";

let fullName: string = `Bob`;
let age: number = 18;
let sentence: string = `Hello, my name is ${fullName}. I'll be ${age + 1} years old next month!`
1
2
3
4
5
  • 字面量
    • 可以使用字面量去指定变量的类型,通过字面量和|可指定变量的取值范围。
    • let color: 'red' | 'blue' | 'black';
      let num: 1 | 2 | 3 | 4 | 5;
      
      1
      2
  • any
    • any表示为任意类型,变量被设置为any类型,相当于关闭了TS对此变量的类型检测。
    • 若声明变量未指定类型且未赋值,则TS会自动设置为any类型。
    • let d: any = 4;
      d = 'hello';
      d = true;
      
      1
      2
      3
  • unknown
    • unknown表示为未知类型的值,实际上就是安全类型的any。
    • let notSure: unknown = 4;
      notSure = 'hello';
      
      1
      2

TS中any类型的变量可以赋值给任意变量,而unknown则不行。

let a: any = 10;
let b: string;
let c: unknown;
b = a; // 可以赋值
b = c; // 报错!
1
2
3
4
5
  • void
    • let unusable: void = undefined;
      
      1
  • never
    • never代表永远不会有返回结果。
    • function fn(msg: string): never {
        // 直接抛出异常,不会返回具体结果
        throw new Error('error!')
      }
      
      1
      2
      3
      4
  • object
    • object表示一个js对象,可以是{},也可以是fuction。
    • {}可以用来指定对象中包含哪些属性,属性后加?代表属性是可选的
      • let obj: {name: string, age?: number};
        // 这样在赋值对象时,age属性可有可无,但name属性必须有。
        obj = {name: 'lwh'};
        
        1
        2
        3
    • 在对对象进行限制时,利用[propName:string]:any设置个数可变的参数。
      • let obj: {name: string, [propName: string]: any};
        // [prop: string]: any 代表参数名类型为string,参数类型为任意值。
        
        1
        2
    • 同样可以对函数变量设置限制
      • let fn: (data1: number, data2: number) => number;
        // 此时fn变量为函数,且参数必须有两个均为number变量,返回类型也为number变量。
        
        1
        2
  • array
    • 类型[]声明:
      • let list: number[] = [1, 2, 3];
        
        1
    • Array<类型>声明:
      • let list: Array<string> = ['a', 'b', 'c'];
        
        1
  • tuple
    • 元组:为固定长度的数组,语法:[类型,类型]。
    •   let list: [string, number];
        list = ['hello', 666];
      
      1
      2
  • enum
  • 枚举:用于给变量设置范围值。
    •   enum Gender {
          Male,
          Famale
        };
      
        let person: {name: string, gender: Gender};
      
        person = {'lwh', Gender.Male}
      
        enum Color {
          Red,
          Yellow,
          Blue
        };
      
        let c: Color = Color.Red;
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
  • |可以声明不同类型,&也可以进行声明,代表同时符合,一般仅在声明对象时使用。
    •   let obj: {name: string} & {age: number};
        // 与直接声明功能相同
        let obj2: {name: string, age: number}
      
      1
      2
      3
  • 类型的别名
    • 对于冗长的类型,使用别名进行代替。
    •   type myType = 1 | 2 | 3;
        let a: 1 | 2 | 3;
        let b: myType;
        // b的类型与a一致,均为 1 | 2 | 3。
      
      1
      2
      3
      4

# 类型断言

  • 有些情况下,变量的类型对于程序员明确,但TS解析器不清楚。此时,需要通过类型断言来告诉编译器变量的类型,(使用类型断言就可以做到unknown类型数据给变量赋值)。断言有以下两种形式:
    • 第一种:变量 as 类型
      • let someValue: unknown = "this is a string";
        let strLength: number = (someValue as string).length;
        
        1
        2
    • 第二种:<类型> 变量
      • let someValue: unknown = "this is a string";
        let strLength: number = (<string>someValue).length;
        
        1
        2

# 编译选项

# 自动编译文件

  • 编译文件时,使用-w指令后,TS编译器会自动监视文件的变化,并在文件发生变化时对文件进行重新编译。相当于nodemon
  • 示例:ts xxx.ts -w

# 自动编译整个项目

  • 若直接使用tsc指令,则可以自动将当前项目下的所有ts文件编译为js文件。
  • 直接使用tsc指令全局编译的前提是配置tsconfig.json文件。
  • tsconfig.json是一个JSON文件,添加配置文件后,只需只需 tsc 命令即可完成对整个项目的编译
  • 配置选项:
    • include
      • 定义希望被编译的文件所在目录。
      • 默认值:["**/*"]**为任意文件夹,*为任意文件名。
      • 示例:
        •   "include":["src/**/*", "tests/**/*"]
          
          1
      • src 和 tests目录下的文件都会被编译。
    • exclude
      • 定义需要被排除在外的目录。
      • 默认值:["**/*"]
      • 示例:
        •   "exclude":["src/**/*", "tests/**/*"]
          
          1
      • src和 tests目录下的文件都不会被编译。
    • extends
      • 定义被继承的配置文件。
      • 默认值:["node_modules","bower_components"]
      • 示例:
        •   "extends": "./configs/base"
          
          1
      • 当前配置文件会自动包含config目录下base.json中的所有配置文件。
    • files
      • 指定被编译文件的列表,只有需要编译的文件少时才会用到。
      • 示例:
        •   "files:" [
              "core.ts",
              "sys.ts",
              "types.ts",
              "scanner.ts"
            ]
          
          1
          2
          3
          4
          5
          6
      • 列表中的文件都会被TS编译器所编译。
    • compilerOptions
      • 编译选项是配置文件中的核心选项。
      • compilerOptions中包含多个子选项,用来配置编译。
      • 项目选项:
        • target
          • 设置ts代码编译的目标版本。
          • 可选值:
            • ES3(默认)、ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext
          • 示例:
            •   "compilerOptions": {
                  "target": "ES6"
                }
              
              1
              2
              3
            • 如上配置,ts代码将会被编译为ES6版本的js代码。
        • lib
          • 配置代码运行时所包含的库(宿主环境)
          • 可选值:
            • ES5、ES6/ES2015、ES7/ES2016、ES2017、ES2018、ES2019、ES2020、ESNext、DOM、WebWorker、ScriptHost ......
          • 示例:
            •   "compilerOptions": {
                  "lib": ["DOM", "ES6"]
                }
              
              1
              2
              3
        • module
          • 设置编译后代码使用的模块化系统。
          • 可选值:
            • CommonJS、UMD、AMD、System、ES2020、ESNext、None
          • 示例:
            •   "compilerOptions": {
                  "module": "CommonJS"
                }
              
              1
              2
              3
        • outDir
          • 设置编译后文件所在目录。
          • 默认情况下,ts文件和编译后js文件会处于相同的目录,设置outDir可以改变位置。
          • 示例:
            •   "compilerOptions": {
                  "outDir": "dist"
                }
              
              1
              2
              3
            • 设置后编译的js文件将会处于dist文件夹内。
        • outFile
          • 将所有的ts文件编译为一个js文件。
          • 默认会将所有编写在全局作用域中的代码合并为一个js文件,如果module指定了NoneSystemAMD则会将模块一起合并到文件中。
          • 示例:
            •   "compilerOptions": {
                  "outFile": "dist/app.js"
                }
              
              1
              2
              3
        • rootDir
          • 指定代码的根目录,默认情况下编译后的文件的目录结构会以最长的公共目录为根目录,通过rootDir手动指定根目录。
          • 示例:
            •   "compilerOptions": {
                  "rootDir": "./src"
                }
              
              1
              2
              3
        • allowJs
          • 是否对js文件进行编译(默认为false)
        • checkJs
          • 是否对js文件进行检查(默认为false)
            • 示例:
            •   "compilerOptions": {
                  "allowJs": true,
                  "checkJs": true
                }
              
              1
              2
              3
              4
        • removeComments
          • 是否删除注释。
          • 默认值:false
        • noEmit
          • 不生成编译后文件
          • 默认值:false
        • noEmitOnError
          • 当有错误时不生成编译后js文件。
          • 默认值:false
        • sourceMap
          • 是否生成sourceMap
          • 默认值:false
      • 严格检查
        • strict
          • 启用所有的严格检查,默认为true,设置后相当于开启了所有的严格检查。
        • alwaysStrict
          • 总是以严格模式对代码编译。
        • noImplicitAny
          • 禁止隐式的any类型。
        • noImplicitThis
          • 禁止类型不明确的this。
        • strictBindCallApply
          • 严格检查applybindcall的参数列表。
        • strictFunctionTypes
          • 严格检查函数的类型。
        • strictNullChecks
          • 严格检查空值。
        • strictPropertyInitialization
          • 严格检查属性是否初始化。
      • 额外检查
        • noFallthroughCasesInSwitch
          • 检查switch语句是否包含正确的break。
        • noImplicitReturns
          • 检查函数是否有隐式的返回值。
        • noUnusedLocals
          • 检查未使用的局部变量。
        • noUnusedParameters
          • 检查未使用的参数。
      • 高级选项
        • allowUnreachableCode
          • 检查不可达代码。
          • 可选值:
            • true:忽略不可达代码。
            • false:不可达代码将引起错误。
        • noEmitOnError
          • 有错误的情况下不进行编译。
          • 默认值:false

# WebPack

  • 通常情况下,实际开发中需要使用构建工具对代码进行打包。
  • 步骤:
    • 1.初始化项目:
      • 进入项目根目录,执行命令npm init -y
      • 自动创建package.json
    • 2.下载构建工具:
      •   npm i -D webpack webpack-cli webpack-dev-server typescript ts-loader clean-webpack-plugin html-webpack-plugin
        
        1
      • 安装包功能:
        • webpack: 构建工具webpack
        • webpack-cli: webpack的命令行工具
        • webpack-dev-server: webpack的开发服务器
        • typescript: ts编译器
        • ts-loader: ts加载器,用于在webpack中编译ts文件
        • html-webpack-plugin: webpack中的html插件,同于自动创建html文件。
        • clean-webpack-plugin: webpack中的清除插件,每次构建都会先清除目录。
    • 3.根目录下创建webpack.config.js配置文件
      •   const path = require('path')
          const HTMLWebpackPlugin = require('html-webpack-plugin')
          const { CleanWebpackPlugin } = require('clean-webpack-plugin')
        
          module.exports = {
            // 指定入口文件
            entry: "./src/index.ts",
        
            // 指定打包文件所在目录
            output: {
              // 指定目录
              path: path.resolve(__dirname, 'dist'),
              // 指定文件名
              filename: 'bundle.js'
            }
        
            // 指定webpack打包时使用的模块
            modules: {
              // 指定加载规则
              rules: [
                {
                  // 指定规则生效的文件
                  test: /\.ts$/,
                  // 指定使用的loader
                  use: 'ts-loader',
                  // 指定要排除的文件
                  exclude: /node-modules/
                }
              ]
            },
        
            // 指定webpack使用的插件
            plugins: {
              // 自动清除dist目录下的文件
              new CleanWebpackPlugin(),
              // 自动生成HTML文件
              new HTMLWebpackPlugin({
                title:'自定义名称',
                // 指定生成html文件的模板
                template: './src/index.html'
              })
            },
        
            // 设置引用的模块
            resolve: {
              extensions: [".ts", ".js"]
            }
          }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
    • 4.根目录下创建tsconfig.json
      •   {
            "compilerOptions": {
              "target": "ES2015",
              "module": "ES2015",
              "strict": true
            }
          }
        
        1
        2
        3
        4
        5
        6
        7
    • 5.增加package.json下的配置
      •   "strict": {
            "test": "echo \"Error: no test specified\" && exit 1",
            "build": "webpack --mode development",
            "start": "webpack serve --open --mode development"
          }
        
        1
        2
        3
        4
        5
    • 6.在src下创建ts文件,命令行执行npm run build对代码编译,或执行npm start启动开发服务器(类似vscode插件live-server)

# Babel

开发中需要使用Babel来对代码进行转换,使其可以兼容到更多的浏览器。

  • 1.安装依赖包
    • npm i -D @babel/core @babel/preset-env babel-loader core-js
    • 共安装了四个包,分别是:
      • @babel/core
        • babel的核心工具
      • @babel/preset-env
        • babel的预定义环境
      • babel-loader
        • babel在webpack中的加载器
      • core-js
        • core-js用来使老版本的浏览器支持新版ES语法。
  • 2.修改webpack.config.js配置文件
    •   module.exports =  {
          //上述省略
          modules: {
            rules: [
              test: /\.ts$/,
              use: [
                {
                  // 指定加载器
                  loader: "babel-loader",
                  // 设置babel
                  options: {
                    // 设置babel的预定义环境
                    preset: [
                      // 指定环境的插件
                      "@babel/preset-env",
                      { 
                        // 要兼容的目标浏览器版本
                        "targets": {
                          "chrome": "88",
                          "ie": "11"
                        },
                        // 指定corejs版本
                        "corejs": "3",
                        // 指定使用corejs为按需引入
                        "useBuiltIns": "usage",
                      }
                    ]
                  }
                }
              ]
            ]
          }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
  • 配置完成后,使用ts编译的文件则会再次被Babel进行处理,使代码可以在大部分浏览器中直接使用。targets配置项用于指定兼容的浏览器版本。

# 面向对象

# 类(class)

类即为对象的模型,要创建对象,必须先要创建类。

  • 定义类:
    •   class 类名 {
          属性名: 类型; 
      
          constructor(参数:类型) {
            this.属性名 = 参数;
          }
      
          方法名() {
            ...
          }
        }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
  • 属性前加readonly代表只读属性,加static代表静态属性,什么都不加则为实例属性。
  • 示例:
    •   class Person {
          name: string;
          age: number;
          static sex: string = 'male'
      
          constructor(name:string, age: number) {
            this.name = name;
            this.age = age;
          }
      
          sayHello() {
            console.log(`Hello, I am ${this.name}!`);
          }
        }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
  • 使用类:
    •   const p = new Person('lwh', 18);
        p.sayHello();
      
      1
      2

# 构造函数

constructor 方法定义,每次创建对象实例时调用,其内部this代表当前对象实例。

class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}
1
2
3
4
5
6

定义类的简便写法:

class Obj {
  constructor(public name: string, public: number) {
    this.name = name;
    this.age = age;
  }
  // 此时不需要在外部定义属性
}
1
2
3
4
5
6
7

# 面向对象的特点

# 封装

  • 对象实质上是属性和方法的容器,用于存储属性和方法。

  • 默认情况下,对象的属性和方法可以任意修改,为保证数据安全性,可以对属性和方法添加修饰符。

  • 只读属性readonly

    • 若在声明属性时添加readonly,则属性变为只读属性后续无法修改。
  • TS中具有三种修饰符:

    • public: 默认情况下的修饰符,可以在任意位置对属性或方法进行访问或修改。
    • private: 私有修饰符,只能在当前类中对属性或方法进行访问或修改。
    • protected: 修饰受保护的属性,只能在当前类或子类中对属性或方法进行访问或修改。
    • 实例:
      • public:
        •   class Person {
              public name: string; // 写或什么都不写都是public
              public age: number;
          
              constructor(name: string, age: number){
                this.name = name; // 可以在类中修改
                this.age = age;
              }
          
              sayHello(){
                console.log(`大家好,我是${this.name}`);
              }
            }
          
            class Employee extends Person{
            constructor(name: string, age: number){
                super(name, age);
                this.name = name; //子类中可以修改
              }
            }
          
            const p = new Person('孙悟空', 18);
            p.name = '猪八戒';// 可以通过对象修改
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
      • protected:
        •   class Person{
                protected name: string;
                protected age: number;
          
                constructor(name: string, age: number){
                  this.name = name; // 可以修改
                  this.age = age;
                }
          
                sayHello(){
                    console.log(`大家好,我是${this.name}`);
                }
              }
          
            class Employee extends Person{
          
                constructor(name: string, age: number){
                    super(name, age);
                    this.name = name; //子类中可以修改
                }
            }
          
            const p = new Person('孙悟空', 18);
            p.name = '猪八戒';// 不能修改         
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
      • private:
        •   class Person {
              private name: string;
              private age: number;
          
              constructor(name: string, age: number) {
                this.name = name;
                this.age = age;
              }
          
              sayHello() {
                console.log(`大家好我是${this.name}`)
              }
            }
          
            class Employee extends Person {
              constructor(name: string, age: number) {
                super(name, age);
                this.name = name; // 子类中不能修改
              }
            }
          
            const p = new Person('孙悟空', 18);
            p.name = '猪八戒'; // 不能修改
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
  • 属性存取器

    • 在类中定义一组用于读取、设置属性的方法,称之为属性的存取器。
    • 读取属性的叫做getter方法,修改属性的方法叫做setter方法。
    • 示例:
      •   class Person {
            private _name: string;
            
            constructor(name: string) {
              this._name = name;
            }
        
            get name() {
              return this._name;
            }
        
            set name(value) {
              this._name = value;
            }
          }
        
          const p = new Person('lwh')l
          console.log(p.name); // 通过getter方法读取name属性
          p.name = 'zzz'; // 通过setter方法设置name属性
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
  • 静态属性

    • 静态属性(方法),又称为类属性。使用静态属性无需创建实例,可通过类直接使用。
    • 使用static关键字定义开头。
    • 示例:
      •   class Tools {
            static PI = 3.1415926;
        
            static sum(num1: number, num2: number) {
              return num1 + num2;
            }
          }
        
          console.log(Tools.PI);
          console.log(Tools.sum(123, 456));
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10

# 继承

  • 通过继承extends可以将其它类中的属性和方法引入到当前类中,可以在不修改类的情况下实现对类的扩展。

  • 示例:

    •   class Animal {
          constructor(public name: string, public age: number) {
            this.name = name;
            this.age = age;
          }
        }
      
        class Dog extends Animal {
          constructor(name: string, age:number, public sex: string) {
            super(name, age);
            this.sex = sex;
          }
        }
      
        const dog1 = new Dog('旺财', 4, 'male');
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
  • 重写:

    • 发生继承时,子类中与父类同名的方法会发生替换。
    • 示例:
      •   class Animal {
            constructor(public name: string) {
              this.name = name;
            }
            sayHello() {
              console.log('Hello!')
            }
          }
        
          class Dog extends Animal {
            sayHello() {
              console.log(`Hello, ${this.name}`)
            }
          }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
  • 抽象类

    • 抽象类是专门用来被其它类所继承的类,只能被其他类继承,不能创建自身实例对象。
    • 使用abstract开头的方法叫做抽象方法,抽象方法没有方法体只能定义在抽象类中,继承抽象类时抽象方法必须要实现
    •   abstruct class Animal {
          // 抽象类中的抽象方法只能定义方法名而无方法体!
          abstruct run(): void;
          bark() {
            console.log('动物在叫!')
          }
        }
      
        class Dog extends Animal {
          // 子类必须实现抽象类中的抽象方法!
          run() {
            console.log('狗在跑!')
          }
        }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14

# 接口(interface)

接口类类似于抽象类,但接口中所有方法和属性都不具有实值,即接口中所有方法都为抽象方法。

  • 接口主要负责定一个类的结构,用于去限制一个对象的结构。
  • 对象只有包含接口中所有的属性和方法时才能匹配接口。
  • 实现类去实现接口时,要保护接口中的所有属性和方法。
  • 示例(检查对象类型):
    •   interface Person {
          name: string;
          age: number;
          sayHello() :void;
        }
      
        function fn(per: Person) {
          per.sayHello();
        }
      
        fn({'lwh', 18, sayHello() {console.log(`Hello! I am ${this.name}~`)}});
      
        // 类似于描述对象类型
        type myType = {
          name: string;
          age: number;
        }
      
        const obj: myType = {
          name: 'lwh',
          age: 18
        }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
  • 示例(实现)
    •   interface Person {
          name: string;
          sayHello(): void;
        }
      
        class Student implements Person {
          constructor(public name: string) {
            this.name = name;
          }
          sayHello() {
            console.log('Hello Vue!');
          }
        }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13

# 泛型

  • 定义一个变量或方法时,有些情况下无法明确要使用的具体类型(返回值、参数、属性的类型不能确定),此时采用泛型。
  • 示例:
  •   function test(a: any): any {
        return a;
      }
    
    1
    2
    3
    • 上述代码,返回值和参数应类型相同,但由于类型不确定故都使用any类型。但any会关闭TS的类型检查,故需要采取泛型解决。
    •   function test<T>(a: T): T {
          return a;
        }
      
      1
      2
      3
    • 调用方式:
      • 直接调用:test(10),类型会由TS自身推断出来。
      • 指定类型:test<number>(10)
  • 可以同时指定多个泛型,泛型间使用逗号分隔。
    •   function fn<T, K>(a: T, b: K): a {
          return a;
        }
      
        fn<string, number>('lwh', 18);
      
      1
      2
      3
      4
      5
  • 类中也可以使用泛型
    •   class MyClass<T> {
          prop: T;
          constructor(prop: T) {
            this.prop = prop;
          }
        }
      
      1
      2
      3
      4
      5
      6
  • 可以使用接口对泛型进行约束,使用extends继承接口的实现类。
    •   interface MyInter {
          length: number;
        }
      
        function fn<T extends MyInter>(a: T): number {
          return a.length;
        }
      
      1
      2
      3
      4
      5
      6
      7
Last Updated: 2023/2/20 11:37:20
等你下课
周杰伦