ts 上

103 阅读5分钟

TypeScript 详解

一、TS的基础概念

1. 什么是TS(与JS的区别)

  • 对比原理:他是JS的一个超集,在原有的语法基础上,添加强类型并切换为基于类的面向对象语言

  • 面向项目:

    • TS - 面向解决大型的复杂项目、架构、代码维护复杂场景
    • JS - 脚本化语言,用于面向简单页面场景
  • 自主检测

    • TS - 编译时,主动发现并纠正错误
    • JS - 运行时,执行报错
  • 类型检测

    • TS - 强类型语言,支持动态和静态的类型检测
    • JS - 弱类型语言,无静态类型选项
  • 运行流程

    • TS - 依赖编译,依靠编译打包实现在浏览器段的运行
    • JS - 可直接在浏览器端运行
  • 复杂特性

    • TS - 模块化、接口、泛型

2. TS的基础类型和语法

  • boolean、string、number、array、null、undefined
//es
let isEnable = false;
let clasas = 'yiban';
let classNum = 2;
let u = undefined;
let n = null;
let arr = [1,2];

//ts
let isEnable: boolean = false;
let class: string = 'yiban';
let classNum: number = 2;
let u:undefined = undefined;
let n: null = null;
// 统一方式 & <>
let arr:number[] = [1,2];
let arr:Array<number> = [1,2];
tuple - 元祖
    let tupleType: [string, boolean] = ['a', false]
enum - 枚举
    // 数字型枚举 - 默认从0开始,依次递增
    enum Score {
        BAD, //0
        NG, //1
        GOOD, //2
        PERFECT //3
    }
    
    let score: Score = Score.BAD
    
    // 字符串类型枚举
    enum Score {
        BAD = 'BAD',
        NG = 'NG,
        GOOD = 'GOOD',
        PERFECT = 'PERFECT,
    }
    // 反向映射
    let scoreName = Score[0]; //BAD
    let scoreVale = Score['Bad']; // 0
    
    // 异构 (没定义就是默认数字型枚举)
    enum Eunm{
        A, // 0
        B, // 1
        C = 'C',
        D = 'D',
        E = 8,
        F, // 9
    }
    
    // 面试题:异构类型每一项的枚举值 => js本质实现(手写一个异构枚举的实现)
    let Enum;
    (function(Enum){
        // 正向
        Enum['A'] = 0;
        Enum['B'] = 1;
        Enum['C'] = 'C';
        Enum['D'] = 'D';
        Enum['E'] = 8;
        Enum['F'] = 9;
        
        // 逆向
        Enum['0'] = 'A';
        Enum['1'] = 'B';
        Enum['8'] = 'E';
        Enum['9'] = 'F' ;
        
    })(Enum || (Enum = {}))
any、unknow、void

any - 绕过所有类型检查 => 类型检测和编译筛查取消

    let value1: any = 123;
    value1 = 'a';
    value1 = false;
    let value2: boolean = value1;
    // 以上均不会报错

unknown - 绕过赋值检查 => 禁止更改传递

    let unknownValue : unknow;
    unknownValue = true;
    unknownValue = 123;
    unknownValue = '123';
    let value1: unknown = unknownValue;
    let value2: any = unknownValue;
    //以上均不会报错
    
    let value3: boolean = unknownValue; //报错

void - 声明返回为空

    function voidFun(): void{
        console.log('1');
    }

never - 永不执行 or 永远error

    function errorGen(msg: string): never{
        throw new Error(msg)
    }
    
    function infiniteLoop(): never{
        while(true){
            //业务代码
        }
    }

object / Object/ {} - 对象

object - 非原始类型 后天创建类型的类型描述/限制

    interface ObjectConstruction {
        create(o: object | null): any;
    }
    
    const proto = {};
    
    Object.create(proto);
    Object.create(null);

Object - 定义了Object类属性

// 保留Object.prototype上的属性
    interface Object {
        constructor: Function;
        toString(): string;
        toLocaleString(): string;
        valueOf(): Object;
        ...
    }
    
    interface ObjectConstructor{
        new(value: any): Object;
        readonly prototype: Object;
    }

{} - 定义空属性对象(想要不报错用下面的interface定义对象)

    const obj = {};
    obj.prop = 'props'; //Error
    obj.toString(); // ok

二、接口 - interface

对行为模块的抽象,具体的行为是有类来实现

    // 描述对象内容
    interface People {
        name: string, 
        age: number,
    }
    
    let zhangsan: People = {
        name: 'zhangsan',
        age: 14
    }
    
    //只读
    interface People {
        readonly name: string, 
        age: number,
    }
    
    // 面试题 (可以延伸为 如何确保const对象不被改写,用ts的只读)
    let arr: number[] = [1,2,3,4];
    let ro: ReadonlyArray<number> = arr;
    ro[0] = 12; //赋值 - Error
    ro.push(5);  // 增加 - Error
    ro.length = 10; // 长度改写 - Error
    arr = ro; // 覆盖 - Error
    
    // 任意可添加属性
    interface People {
        readonly name: string, 
        age: number,
        [propName: string]: any; // 用来添加任意属性的
    }
    
    const c1 = {name: 'lisi'};
    const c2 = {name: 'wangwu', time: 16};
    const c3 = {name: 'bingliu', age: 20};

三、交叉类型 - &

合并

    interface A{
        inner: D;
    }
    
    interface B{
        inner: E;
    }
    
    interface C{
        inner: F;
    }
    
    interface D{
        d: boolean;
    }
    
    interface E{
        e: string;
    }
    
    interface F{
        f: number;
    }
    
    type ABC = A & B & C;
    
    let abc: ABC = {
        inner: {
            d: false,
            e: 'className',
            f: 5,
        }
    }
    

合并冲突

    interface A{
        c:string;
        d:string;
    }
    interface B{
        c:number;
        d:string;
    }
    
    type AB = A & B;
    let ab: AB;
    // 合并的关系是‘且’ => c只能是never

四、 断言 - 类型的声明和转换(和编译器做了一个告知交流)

编译时作用

    // 尖括号形式
    let anyValue: any = 'h1';
    let anyLength: number =  (<string>anyValue).lenght;
    
    // as 声明
    let anyValue: any = 'h1';
    let anyLength: number =  (anyValue as string).lenght;
    
    // 非空判断 - 只确定不是空
    type ClassTime = () => number;
    const start = (ClassTime: ClassTime | undefined) {
        ...
        let time = ClassTime!; // 具体类型待定 但是非空确认
    }
    
    // 面试题
    const tsClass: number | undefined = undefined;
    const ts: number = tsClass!;
    console.log(ts); 
    // 转义成
    const tsClas s= undefined;
    const ts = tsClass!;
    console.log(ts); // undefined
    
    // 肯定断言 - 肯定化保证赋值
    let score: number;
    startClass();
    console.log('' + score);
    
    function startClass(){
        score = 5;
    }
    // let score!: number; -- 提前告知肯定化赋值

五、类型守卫 - 语法规范范围内,额外的确认

多态 - 多种状态(多种类型)

in - 定义属性场景下内容的确认

    interface Teacher(){
        name: string;
        courses: string[];
    }
    interface Student(){
        name: string;
        startTime: Date
    }
    type Class = Teacher | Student;
    
    function startCourse(cls: Class){
        if('courses' in cls){
            console.log('Courses:' + cls.courses) 
        }
        if('startTime' in cls){
            console.log('startTime:' + cls.startTime) 
        }
    }

typeof / instanceif - 类型分类场景下的身份确认

    function class(name: string, score: string | number){
        if(typeof score === 'nubmer'){
            return 'teacher'
        }
        if(typeof score === 'string'){
            return 'student'
        }
    }
    
    const getName = (cla: Class){
        if(cls instanceof Teacher){
            return 'teacher'
        }
        if(cls instanceof Student){
            return 'student'
        }
    }

六、 TS进阶

1. 函数重载 - 复用(对实际数据的类型做不同的匹配)

    class Course{
        start(name:number, score: number): number;
        start(name:string, score: string): string;
        start(name:string, score: number): string;
        start(name:number, score: string): string;
        start(name: Conbinable, score: Conbinable){
            if (typeof name === 'string' || typeof score === 'number'){
                return 'children'
            }
        }
    }
    
    const course = new Course();
    course.start('zhangsan', 5);

2. 泛型 - 复用(让模块可以支持多种类型数据 - 让类型声明和值一样, 可以被赋值和传递)

    function startClass <T, U>(name: T, score: U) : T {
        return name + score;
    }
    
    console.log(startClass<Number, String>('zhangsan', 5));
    // T、U、K - 键值类、V - 值、 E - 节点、元素

3. 装饰器 - decorator

需安装

    // 类装饰器
    function fun(target: Function): void{
        target.prototype.startStude = function(): void{
            // 通用功能
        }
    }
    
    // 属性装饰器
    function propsWrapper(target: any, key: string){
        //属性的统一操作
        Object.defineProperty(target, key, {
            ...
        })
    }
    
    // 方法装饰器 - target:Object, propertyKey: string, descriptor: TypePropertyDescript
    
    @fun // 类装饰器
    class Course {
        constructor(){
            //包含了startStude方法 
        }
        
        @propsWrapper // 属性装饰器
        public name: string;
        
        @methodDec // 方法装饰器 
    }