TypeScript学习总结

169 阅读5分钟

一. TS的基本概念

1、 TS的本质

是Js的一个超集,在原有的语法基础上,添加了可选的静态类型和基于类的面向对象编程

  • 类型检测

    js:弱类型,无静态类型选项

    ts:强类型,支持动态和静态类型的检测和拦截

  • 自主检测

    js:runtime, 报错

    ts:编译期间,主动发现并报出错误

  • 运行流程

    js:直接在浏览器中运行

    ts:依赖编译,依赖工具化体系

  • 面向项目

    js:脚本化语言,面向单一简单的场景

    ts:面相解决大型复杂应用,有利于代码设计以及维护

  • 复杂特性

    ts:模块化,接口,泛型

    安装运行

    
        npm install -g typescript
        
        tsc -v
        
        tsc test.ts
    
     // ts所有的类型检测,以及语法检测的阶段都是在编译时
      
     // 面试:黑框错误是什么时候报出来的?--编译ts时报的错
    
    

2.ts基础类型及写法

boolean string number array null undefined

    //es
    let isEnable = true
    let class = 'zhangsan'
    let classNum = 2
    let u = undefined
    let n = null
    let classArr = ['basic', 'execute']
    
    //ts
    let isEnable:boolean = true
    let class: string = 'zhangsan'
    let classNum: number = 2
    let u: undefined = undefined
    let n: null = null
    let classArr: Array<string> = ['basic', 'execute']
    let classArr: string[] = ['basic', 'execute']
    
  • tuple 元组
    let tupleType:[string, boolean]
    tupleType = ['zhangsan', true]
  • enum 枚举

    //数字类枚举,默认从零开始,从上往下依次递增
    enum Score {
        BAD,
        NG,
        GOOD,
        PERFECT
    }
    
    let score: Score = Score.BAD;
    
    //字符串类型枚举
    enum Score {
        BAD = 'BAD',
        NG = 'NG',
        GOOD = 'GOOD',
        PERFECT = 'PERFECT'
    }
    
    //反向映射
    let score = Score.BAD
    let scoreName = Score[0] //BAD
     let scoreName = Score['BAD'] //0
     
    //异构枚举 - 梳理字符串 => 数字
    enum Enum {
        A,
        B,
        C = 'C',
        D = 'D',
        E = 6,
        F,
    }
    //面试题:指出异构的枚举值,并手写转化js实现
    let Enum;
    (function(Enum) {
      //正向
        Enum['A'] = 0
        Enum['B'] = 1
        Enum['C'] = 'C'
        Enum['D'] = 'D'
        Enum['E'] = 6
        Enum['F'] = 7
    
      //反向
        Enum[0] = 'A'
        Enum[1] = 'B'
      
        Enum[6] = 'E'
        Enum[7] = 'F'
    })(Enum || (Enum = {}))
    
    
    
  • any unknown void

    //any - 绕过所有的类型检查 => 类型检测和编译筛查全部失效
    let anyVal: any = 123;
    anyVal = 'anyVal';
    anyVal = false;
    
    let val1: boolean = anyVal
    
    //unknown - 绕过了赋值检查 => 禁止更改传递
    let unknownVal: unknown;
    unknownVal = 123;
    unknownVal = 'unknownVal';
    
    let val2: unknown = unknownVal //ok
    let val3: any = unknownVal //ok
    let val4: boolean = unknownVal //NOK
    
    //void - 声明函数无返回值
    function voidFun(): void {
        console.log('void function')
    }        
    
    //never - 函数用不返回
    function error(msg: string):never {
        throw new Error(msg)
    }
    
    function longlongloop(): never {
        while(true) {
            //业务
        }
    }
    
    
  • Object | object | {} - 对象

    //Object - 所有Object类的实例类型
    //1.有值
    //2. toString
    //3.值的对象属性与Object接口中属性冲突时,TSC会提示错误
    function fun1(x: Object){
    
    }
    fun1({
        name: 'zhangsan'
    })
    
    const obj1: Object = {
        toString() {
            return 'zhangsan'
        }
    }
    
    //object - 表示非原始类型
    //1. 没有值
    //2.不具备hasOwnProperty
    //3.如果值对象属性与Object接口中属性冲突,TSC不会提示错误
    
    //空对象 {} - 描述一个没有任何成员的对象,
    //在赋予属性前,任何访问该对象任意属性的操作,都会被tsc编译抛出错误
    
    const obj = {}
    
    obj.name = 'zhangsan' //prop does not exist on type {}

二、接口-interface

  • 对行为的一种抽象,具体的行为由类实现
    interface Class {
        name: string;
        time: number;
       
    }
    
    let if: Class = {
        name: 'ts',
        time: 2
    }
    
    //只读 & 任意
     interface Class {
        readonly name: string;
        time: number;
    }
    
    //面试题 - 只读和es中的引用是不同的 
    //const 
    let arr: number[] = [1,2,3,4]
    let ro: ReadOnlyArray<number> = arr
    
    //对ro进行任何操作,都会报ERROR
    
    interface Class {
        readonly name: string;
        time: number;
        [propName: string] : string | number;//不限制添加
    }
    
    

三、交叉类型 - &

    interface A {x: D}
    interface B {x: E}
    interface C {x: F}
    
    interface D {d: boolean}
    interface E {e: string}
    interface F {f: number}
    
    type ABC = A & B & C //类群,可以由若干个接口整合和计算
    
    let abc: ABC = {
        x: {
            d: false,
            e: 'zhangsan',
            f: 5
        }
    }
    
    //合并冲突
    interface A {
        c: string,
        d: string
    }
    
    interface B {
        c: number,
        e: string,
    }
    
    type AB = A & B
    
    let ab: AB = {
        d: 'class',
        e: 'zhangsan'
    }
    
    //c: never, 且关系

四、断言 - 类型的声明、转换(开发者和编译器的告知交流)

  • 编译状态产生的声明作用
    let anyVal: any = 'hi zhangsan'
    let anyLen: number = (<string>anyVal).length
     let anyLen: number = (anyVal as string).length
     
     type ClassTime = () => number
     
     const start = (classTime: ClassTime | undefined) => {
          let num = ClassTime ! ()//具体类型待定,但是确认是非空
     }
    

五、类型守卫 - 保障在语法规定的范围之内做额外的确认

    interface Teacher {
        name: string,
        courses: string[],
        score: number
    }
    
    interface Student {
        name: string,
        startTime: number,
        score: string
    }
    
    type Class = Teacher | Student
    
    //in - 是否包含某种属性
    function startCourse(cls: Class) {
        if('courses' in cls) {
            //老师
        }
        if('startTime' in cls) {
            //学生
        }
    }
    
    //typeof / instanceof
    
    function startCourse(cls: Class) {
        if(typeof cls.score === 'number') {
            //老师
        }
        if(typeof cls.score === 'string') {
            //学生
        }
    }
    
    class Teacher {}
    class Student {}
    
     function startCourse(cls: Class) {
        if( cls instanceof Teacher) {
            //老师
        }
        if(cls instanceof Student) {
            //学生
        }
    }

六、TS进阶方案

1.函数重载

    class Class {
        start(name: number, score: number): number;
        start(name: string, score: string): string;
        start(name: string, score: number): number;
        
        start(name: Combinable, score: Combinable): {
            if (typeof name === 'number' && type score === 'number') {
                //处理
            }
            if (typeof name === 'string' && type score === 'string') {
                //处理
            }
            if (typeof name === 'string' && type score === 'number') {
                //处理
            }
        };
    }

2.泛型 - 重用

    function startClass <T, U>(name: T, score: U): T{
        //逻辑
    }
    
    function startClass <T, U>(name: T, score: U): string{
        //逻辑
    }

3.装饰器 - decorator

    
    function Zhao (target: Function): void {
        target.prototype.startClass = function (): void {
            //逻辑
        }
    }
    
    @Zhao
    class Course {
        constructor() {
            //业务逻辑
            
        }
    }
    
    
    //#####################################
    
    function nameWrapper(target: string | number, key: string): void {
        Object.defineProperty(target, key, {})
    } 
    
     class Course {
        constructor() {
            //业务逻辑
            
        }
        
        @nameWrapper
        public name: string;
    }
    
    
    
    

补充


// 插入
// readonly | partial | required | omit | pick

// partial -- 可选的,不可以添加interface中不存在的属性
// required -- 必选的,
// omit
// pick -- 选择, 挑选出需要的属性

 interface Class {
   name: string,
   time: number,
   department: string
 }

 type newCls = Partial<Class>

// 相等于
 type newCls2 = {
   name?: string | undefined,
   time?: number | undefined,
   department?: string | undefined
 }


/ type newCls = Required<Class>

// 相等于
 type newCls2 = {
   name?: string | undefined,
   time?: number | undefined,
   department?: string | undefined
 }

// omit
 interface Student {
   name: string,
   age: number,
   score: number
 }

// 下面两项等价,student中只选择name和score
 type PickStudent = Pick<Student, 'name' | 'score'>
 type OmitStudent = Omit<Student, 'age'>//忽略了age