• 【TypeScript】基础知识学习笔记



    theme: channing-cyan

    TypeScript的特点:

    • JavaScript的超集,满足所有的JS语法
    • 含有面向对象的静态类型

    起步安装:1、npm i typescript -g 2、tsc 文件名

    一、TS的基本数据类型

    基本数据类型:number、boolean、string、undefined、null、symbol、bigint、void

    当中的类型有大小写的区分:大写的类型是给对象使用,小写的类型是原生类型

    二、TS的任意类型

    任意数据类型:any、unknown

    any

    any类型可以赋值给任意类型的,也可以被任意类型的赋值。

    unknown

    unknown类型的特点:

    • unknown类型只能赋值给自身或者any
    • unknown类型不能调用任何属性和方法
    • unknown类型比any更加安全

    额外知识

    object、Object以及{}的三个区别:

    • Object是跟原型链有关的,原型链顶层是Object,所以值的类型和引用类型都是指向Object,所以包含所有类型
    • object是所有非值类型的类型
    • {}是与第一个一样,但是字面量模式下不能修改值

    三、接口类型

    interface的作用:定义一种约束,让数据结构满足约束的格式

    1、当interface重名的时候,会进行合并
    ˋˋˋjs
    ˋˋˋ
    2、任意的索引,让接口属性动态化
    3、可选属性
    4、只读属性
    5、接口的继承,可以继承多个接口,最后结果就是将多个接口进行合并,以逗号分隔
    6、定义函数类型

    四、数组类型

    1、类型[]

    最简单和最直观表示数组类型的方法,一维就是一个括号,二维就是两个括号,后面的以此类推

    let arr: number[] = [1, 2, 3];
    
    • 1
    2、用接口表示数组
    // 利用接口的任意索引属性来实现数组结构的类型的定义
    interface NumArray {
      [index: number]: number;
    }
    
    let arr: NumArray = [1, 2, 3];
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    3、对于arguments这个伪类数组的处理

    1)采用TS的内置对象IArguments
    IArguments内部实现:

    interface IArguments {
      [index: number]: number;
      length: number;
      callee: Function;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    五、函数类型

    1、函数定义类型和返回值、箭头函数定义类型和返回值
    // 定义普通函数类型
    function add(num1: number, num2: number): number {
      return num1 + num2;
    }
    // 定义箭头函数的参数类型和返回值
    const descrease = (num1: number, num2: number): number => {
      return num1 - num2;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    2、函数重载

    重载就是函数名一样,但是参数不一样,从而可以保证不同的时候调用不同的参数

    3、接口定义函数
    // 接口定义函数
    interface Add {
      (num1: number, num2: number): number;
    }
    
    const add: Add = (num1: number, num2: number): number => {
      return num1 + num2;
    };
    
    add(1,2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    六、联合类型、交叉类型、类型断言

    联合类型就是扩展某个变量的类型,让变量可以是这个当中任一个类型,通过‘|’
    交叉类型就是扩张某个变量的类型,和extends类似,将合并信息,通过‘&’
    类型断言可以对某个变量改成固定的类型,但是使用的时候需要注意,可能语法错误提示没有了,但是会导致一些语法错误

    七、TS的内置对象

    JavaScript当中有许多的内置对象,这些内置对象可以在TypeScript当做定义好的类型来使用

    代码雨TS练习:

    let canvas = document.querySelector('#canvas') as HTMLCanvasElement;// 获取canvas元素
    let ctx = canvas.getContext('2d') as CanvasRenderingContext2D;// 画布渲染内容
    canvas.height = screen.availHeight;// 最大的窗口高度
    canvas.width = screen.availWidth;// 最大的窗口宽度
    
    let str: string[] = 'XZSDASRWQJKHEWQKHEJLKQWHEKQWHE'.split('');
    let Arr = Array(Math.ceil(canvas.width / 10)).fill(0);
    console.log(Arr);
    const rain = () => {
      ctx.fillStyle = 'rgba(0,0,0,0.5)';// 背景颜色
      ctx.fillRect(0, 0, canvas.width, canvas.height);// 背景的大小
      ctx.fillStyle = '#0f0';// 字体颜色
      Arr.forEach((item, index) => { // 数组用来实现代码雨高度的改变
        ctx.fillText(
          str[Math.floor(Math.random() * str.length)],
          index * 10,
          item + 10
        );
        Arr[index] =
          item >= canvas.height || item > 10000 * Math.random() ? 0 : item + 10;
      });
    };
    
    setInterval(rain, 100);
    
    
    • 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

    八、class类

    1、定义一个简单的类

    TypeScript的类的定义和java当中类的定义一样,需要先声明属性,但是JS中可以直接使用constructor中this去直接指向实例对象来添加属性

    class Person {
      name: string;
      age: number;
    
      constructor(name: string, age: number) {
        this.name = name;
      }
    
      run() {}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    2、类的修饰符
    • protected:定义的私有变量只能在内部和继承的子类中访问,不能在外部访问
    • private:私有修饰符,只能在类的内部访问调用
    • public:公开修饰符,都可以访问调用
    • static:静态修饰符,只有通过这个类名才可以访问调用

    虽然有这些关键字和java很类似,但是它的本身还是JS,TS只是做了类型校验,会有语法提示而已,并不会去约束语法

    class Person {
      public name: string;
      private age: number;
    
      constructor(name: string, age?: number) {
        this.name = name;
      }
    
      static run() {}
    
      getName() {
        console.log(this.name);
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    3、interface定义类
    4、抽象类

    九、TS元组类型

    元组类型定义:是一个数量固定,元素可以类型不同的集合。
    好处:可以将多个元素作为一个单元传递
    基本语法:

    // 当对arr数组进行重新赋值的时候如果超过了固定数量将会报语法提示,但是对于一些push方法都不会有语法错误提示
    let arr:  [string, boolean] = ['1', false];
    
    
    • 1
    • 2
    • 3

    使用readonly关键字可以保证无法对这个元组进行任何操作,例如数组进行push方法也会提示语法错误

    let arr: readonly [string, boolean] = ['1', false];
    
    arr = ['123', true];
    
    • 1
    • 2
    • 3

    十、枚举类型

    1、数字枚举

    数字枚举默认是从0开始不断递增,如果自己对定义了初始值将会自动递增

    enum Color {
      Red,
      Green,
      Blue,
    }
    
    console.log(Color.Green); // 1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2、字符串枚举

    字符串没有自动增长的行为,因此字符串可以很好地序列化。字符串枚举必须保证每一个成员都要有字符串字面量

    enum Color {
      Red = 'red',
      Green = 'green',
      Blue = 'bule',
    }
    
    console.log(Color.Green); // green
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    3、异构枚举

    异构枚举就是数字枚举和字符串枚举一起使用,混合在一起

    enum Color {
      No = 'No',
      Yes = 1,
    }
    
    • 1
    • 2
    • 3
    • 4
    4、const枚举
    • const声明的枚举会被编译完成常量
    const enum Types{
        NO = 'No',
        Yes = 1
    }
    
    • 1
    • 2
    • 3
    • 4
    • 普通声明的枚举会被编译完成为一个对象
    enum Color {
      Red = 'red',
      Green = 'green',
      Blue = 'bule',
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    5、反向映射

    枚举成员都可以有正向映射和反向映射,正向映射就是name->value,value->name
    注意:字符串枚举成员不会有反向映射

    enum Enum {
      fall,
    }
    
    let a = Enum.fall;
    console.log(a); // 0
    let nameEnum = Enum[a];
    console.log(nameEnum); // fall
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    十二、Never类型

    作用:表示不应该存在的状态

    它和void的差异:

    • void它是没有返回值但不会出错,never它是没有返回值只会有异常
    • never在联合类型当中会被直接移除

    十四、泛型

    作用:它就是提供一个动态的类型,你可以使用不同的泛型参数名,只要在数量和使用方式上对应就行

    function showArray<T>(a:T,b:T):Array<T>{
      return [a,b]
    }
    
    showArray(1,2)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1、泛型约束

    作用:对泛型进行类型的约束,保证它具有一定的属性,能够提供语法提示

    interface Len {
      length:number
    }
    
    function showArrayLength<T extends Len>(arg:T){
      arg.length
    }
    
    showArrayLength([1,2])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用keyof约束对象

    function prop<T,K extends keyof T>(obj:T,key:K){
      return obj[key]
    }
    
    let obj = {a:'1',b:'2'}
    
    prop(obj,'c') //Argument of type '"c"' is not assignable to parameter of type '"a" | "b"'
    prop(obj,'a')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    2、泛型类

    它的定义和定义函数方式一致,在类名后面加<类型>

    十五、tsconfig.json

    生成tsconfig.json文件:通tsc --init生成
    详细的ts的配置文件:

    "compilerOptions": {
      "incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
      "tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
      "diagnostics": true, // 打印诊断信息 
      "target": "ES5", // 目标语言的版本
      "module": "CommonJS", // 生成代码的模板标准
      "outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
      "lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
      "allowJS": true, // 允许编译器编译JS,JSX文件
      "checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
      "outDir": "./dist", // 指定输出目录
      "rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
      "declaration": true, // 生成声明文件,开启后会自动生成声明文件
      "declarationDir": "./file", // 指定生成声明文件存放目录
      "emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
      "sourceMap": true, // 生成目标文件的sourceMap文件
      "inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
      "declarationMap": true, // 为声明文件生成sourceMap
      "typeRoots": [], // 声明文件目录,默认时node_modules/@types
      "types": [], // 加载的声明文件包
      "removeComments":true, // 删除注释 
      "noEmit": true, // 不输出文件,即编译后不会生成任何js文件
      "noEmitOnError": true, // 发送错误时不输出任何文件
      "noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
      "importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
      "downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
      "strict": true, // 开启所有严格的类型检查
      "alwaysStrict": true, // 在代码中注入'use strict'
      "noImplicitAny": true, // 不允许隐式的any类型
      "strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
      "strictFunctionTypes": true, // 不允许函数参数双向协变
      "strictPropertyInitialization": true, // 类的实例属性必须初始化
      "strictBindCallApply": true, // 严格的bind/call/apply检查
      "noImplicitThis": true, // 不允许this有隐式的any类型
      "noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
      "noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
      "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
      "noImplicitReturns": true, //每个分支都会有返回值
      "esModuleInterop": true, // 允许export=导出,由import from 导入
      "allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
      "moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
      "baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
      "paths": { // 路径映射,相对于baseUrl
        // 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
        "jquery": ["node_modules/jquery/dist/jquery.min.js"]
      },
      "rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
      "listEmittedFiles": true, // 打印输出文件
      "listFiles": true// 打印编译的文件(包括引用的声明文件)
    }
     
    // 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
    "include": [
       "src/**/*"
    ],
    // 指定一个排除列表(include的反向操作)
     "exclude": [
       "demo.ts"
    ],
    // 指定哪些文件使用该配置(属于手动一个个指定文件)
     "files": [
       "demo.ts"
    ]
    
    • 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
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    十六、namespace命名空间

    作用:避免全局变量造成污染

    • 通过export暴露
    • 通过namespace关键字定义

    当两个命名空间重名的时候会进行合并

    十八、声明文件declare

    作用:提供语法提示和代码补全等功能

    使用:通过.d.ts文件去写declare声明

    Ts写发布订阅模式

    interface EventFace {
      on: (name: string, callback: Function) => void;
      emit: (name: string, ...args: Array<any>) => void;
      off: (name: string, fn: Function) => void;
      once: (name: string, fn: Function) => void;
    }
    
    interface List {
      [key: string]: Array<Function>;
    }
    
    class Dispatch implements EventFace {
      list: List;
      constructor() {
        this.list = {};
      }
    
      on(name: string, callback: Function) {
        const callbackList: Array<Function> = this.list[name] || [];
        callbackList.push(callback);
        this.list[name] = callbackList;
      }
    
      emit(name: string, ...args: Array<any>) {
        let eventName = this.list[name];
        if (eventName) {
          eventName.forEach((fn) => {
            fn.apply(this, args);
          });
        } else {
          console.error('该事件未被监听');
        }
      }
    
      off(name: string, fn: Function) {
        let eventName = this.list[name];
        if (eventName) {
          let index = eventName.findIndex((fns) => fns === fn);
          eventName.splice(index, 1);
        } else {
          console.error('该事件未被注册');
        }
      }
    
      once(name: string, fn: Function) {
        let decor = (...args: Array<any>) => {
          fn.apply(this, args);
          this.off(name, decor);
        };
        this.on(name, decor);
      }
    }
    
    let myEvent = new Dispatch();
    
    myEvent.on('show', () => {
      console.log('展示');
    });
    myEvent.on('show', () => {
      console.log('展示1', arguments);
    });
    myEvent.once('show', () => {
      console.log('helloworld');
    });
    myEvent.emit('show', 'zjt', 'hello');
    
    
    • 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
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    二十四、partial和pick

    • partial

    作用:快速设置T中的所有属性为可选

    type Person = {
      name:string
      age:number
    }
    /**
     * type p = {
        name?: string;
        age?: number;
    }
     */
    type p = Partial<Person>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    源码:

    // 通过遍历T类型的所有属性来实现可选
    type MyPartial<T> = {
      [p in keyof T]?:T[p]
    }
    
    • 1
    • 2
    • 3
    • 4
    • pick

    作用:在T中选取指定一组属性,返回一个新的类型定义

    type Person = {
      name: string;
      age: number;
      text: string;
      address: string;
    };
    
    type Ex = 'text' | 'age';
    
    type A = Pick<Person, Ex>;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    源码:

    // k被进行泛型约束,确保K类型一定在T里面,再通过遍历K来实现类型的选定
    type MyPick<T, K extends keyof T> = {
      [P in K]: T[P];
    };
    
    • 1
    • 2
    • 3
    • 4

    二十五、readonly和record

    • readonly

    作用:将T类型的所有属性变为只读属性

    type Person = {
      name:string
      age:number
    }
    /**
     * type p = {
        readonly name: string;
        readonly age: number;
    }
     */
    type p = Readonly<Person>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    源码:

    type MyReadonly<T> = {
      readonly [P in keyof T]:T[P]
    }
    
    • 1
    • 2
    • 3
    • record

    作用:根据类型参数来映射出一个key,value形式的类型出来

    type petsGroup = 'dog' | 'cat' | 'fish'
    
    interface IPetInfo{
      name:string,
      age:number
    }
    
    /**
     * type IPets = {
        dog: IPetInfo;
        cat: IPetInfo;
        fish: IPetInfo;
    }
     */
    type IPets = Record<petsGroup,IPetInfo>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    源码:

    type MyRecord<T extends keyof any,K> = {
      [P in T]:K
    }
    
    • 1
    • 2
    • 3

    二十七、infer关键字

    作用:

    • 定义关键字起占位效果
    type zhanwei<T> = T extends Array<infer U> ? U : T;
    
    type A = zhanwei<(string | Symbol)[]>;
    
    • 1
    • 2
    • 3
    • 类型提取
    type Arr = ['a','b','c']
     
    type First<T extends any[]> =  T extends [infer First,...any[]] ? First : []
     
    type a = First<Arr>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 递归
    type Arr = ['a', 'b', 'c'];
    
    type Reverse<T extends any[]> = T extends [infer first, ...infer rest] ? [...Reverse<rest>,first] : [];
    
    type a = Reverse<Arr>;
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二十八、extends关键字

    作用:

    • 继承/拓展
    • 约束
    • 分配
  • 相关阅读:
    办理广播电视节目制作许可证? 你需要知道这些
    智慧园区的核心本质是什么?
    C++ - 类型转换
    RocketMQ如何实现消息的顺序性
    shell-流程控制case语句
    Spring for Apache Kafka概述和简单入门
    使用VisualStudio2022制作安装包
    解决 MyBatis-Plus + PostgreSQL 中的 org.postgresql.util.PSQLException 异常
    Nmap使用教程图文教程(超详细)
    SpringMVC:拦截器(动力)
  • 原文地址:https://blog.csdn.net/Triumph_light/article/details/132650187