【typescript】总结typescript一些类型和使用

TypeScript 详解

一、TS 基础概念

1. 什么是TS

a. 对比原理

  • 是JS的一个超集,在原有基础上,添加了
    可选静态类型
    基于类的面向对象编程
    TS的使用场景

面向项目:
TS - 面向解决大型复杂项目,繁杂架构以及代码维护的场景
JS - 脚本化语言,用于面向简单页面场景

自主检测:
TS - 编译期间,主动发现并指出错误
JS - 无编译阶段

类型检测:
TS - 强类型
JS - 弱类型

运行流程:
TS - 依赖编译,依靠编译打包后,翻译成JS
JS - 可直接运行于浏览器中

复杂特性:
TS - 模块化、泛型、接口

b. 安装运行

    npm install -g typescript
    tsc -v

    tsc test.ts
    // 面试点:ts相较于js优势,功能 => 上面的四个点
    // ts是如何实现这些功能的 => 多了编译时 => ts官方编译器 / babel
2. TS基础类型与写法
  • boolean string number array null undefined
// es
let isEnabled = true;
let class = 'ts';
let classNum = 2;
let classArr = ['basic', 'execute'];

// ts
let isEnabled: boolean = true;
let class: string = 'ts';
let classNum: number = 2;
let classArr: string[] = ['basic', 'execute'];
let classArr: Array<string> = ['basic', 'execute'];
  • tuple - 元组
    let tupleType: [string, boolean]
    tupleType = ['ts', true];
  • enum - 枚举
    // 数字类枚举 - 默认从零开始,依次递增
    enum Score {
        BAD,
        NG,
        GOOD,
        PERFECT
    }
    let score: Score = Score.BAD;

    // 字符串类型
    enum Score {
        BAD = 'BAD',
        NG = 'NG',
        GOOD = 'GOOD',
        PERFECT = 'PERFECT'
    }

    // 反响映射
    enum Score {
        BAD,
        NG,
        GOOD,
        PERFECT
    }
    let scoreName = Score[0];  // 'BAD'
    let scoreValue = Score['BAD']; // 0

    // 异构 - 字符串 + 数字
    enum Score {
        A,
        B,
        C = 'C',
        D = 'D',
        E = 6,
        F,
    }

    // 面试题:手写实现一个异构枚举
    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
    1. any类型是TypeScript类型系统中的顶级类型,它表示任意类型的值。
      当一个变量的类型被指定为any时,TypeScript编译器将不会对它进行类型检查,你可以对它进行任何操作,包括获取不存在的属性、调用任何方法等。
      使用any类型会使得TypeScript退化成JavaScript,因为关闭了类型检查,所以应该尽量避免使用any类型。
    // any - 绕过所有检查 => 类型检测和编译筛查全部失效
    let anyValue: any = 123;

    anyValue = 'anyValue';
  1. unknown类型是TypeScript 3.0中引入的,它是TypeScript类型系统中的另一种顶级类型。
    unknown类型表示任何值,但是与any类型不同的是,unknown类型的值在执行大多数操作之前需要进行类型检查或类型断言。
    这意味着unknown类型提供了比any类型更安全的类型检查。
    // unknown - 绕过赋值检查 => 禁止更改传递
    // 传递
    let unknownValue: unknown;

    unknownValue = 'unknownValue';
    let value1: unknown = unknownValue; // OK
    let value2: any = unknownValue; // OK
    let value3: boolean = unknownValue; // NOK
  1. void类型表示没有任何类型,通常用于函数没有返回值的情况。
    当一个函数的返回类型是void时,它实际上表示该函数不期望返回任何值(或者说返回undefined)。
    // void - 声明函数返回值
    function voidFunction(): void {
        console.log('no return');
    }
  1. never类型表示不应该出现的类型,它通常用于函数永远不会返回值的情况,例如函数抛出异常或进入无限循环。
    never类型是所有类型的子类型,可以赋值给任何类型,但是没有任何类型可以赋值给never类型(除了never本身)。
    使用never类型可以帮助TypeScript编译器进行更严格的类型检查,以确保代码的完整性。
    // never - 永不返回
    function error(msg: string): never {
        throw new Error(msg);
    }
    function longlongloop(): never {
        while(true) {}
    }
  • object | Object | {} - 对象
    // object - 非原始类型
    // 声明文件
    interface ObjectConstrutor {
        create(o: object | null): any;
    }

    // 逻辑文件
    const proto = {
        a: 1
    };
    Object.create(proto); // OK

    // Object - 原型属性
    // Object.prototype上属性
    interface Object {
        constructor: Function;
        toString(): string;
        valueOf(): Object;
    }

    // {} 空对象 - 没有成员的对象
    const a = {} as A;
    a.class = 'es';
    a.age = 30;

二、接口 - interface

  • 对行为的抽象,具体行为由类实现
    interface Class {
        name: string;
        time: number;
    }
    
    let course: Class = {
        name: 'ts',
        time: 2
    }

    // 只读
    interface Class {
        readonly name: string;
        time: number;
    }
    // 任意
    interface Class {
        readonly name: string;
        time: number;
        [propName: string]: any;
    }
    // 面试题 - 和JS的引用不同 < = > const
    let arr: number[] = [1, 2, 3, 4];
    let ro: ReadonlyArray<number> = arr;

    ro[0] = 12;  // Error - 赋值
    ro.push(5);  // Error - 增加
    ro.length = 100; // Error - 长度改写
    
    arr = ro;       // Error - 覆盖

三、交叉类型

    // 合并
    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: 'class',
            f: 5
        }
    }

    // 合并冲突
    interface A {
        c: string;
        d: string;
    }
    interface B {
        c: number;
        d: string;
    }

    type AB = A & B;
    // 合并的关系是且 => c: never
四、断言 - 类型声明、转换
    // 尖括号
    let anyValue: any = 'hi ts';
    let anyLength: number = (<string>anyValue).length;  // 阶段性声明

    // as声明
    let anyLength: number = (anyValue as string).length;

    // 非空判断
    type ClassTime = () => number;

    const start = (classTime: ClassTime | undefined) => {
        let num = classTime!(); // 确认一定不会为空
    }

    // 面试题
    const tsClass: number | undfined = undefined;
    const course: number = tsClass!;
    // 使用的意义 => 告知编译器,运行时下,会被赋值

五、类型守卫

    interface Teacher {
        name: string;
        courses: string[];
        score: number;
    }
    interface Student {
        name: string;
        startTime: Date;
        score: string;
    }

    type Class = Teacher | Student;

    function startCourse(cls: Class) {
        if ('courses' in cls) {
            // teacher的逻辑
        }
        if ('startTime' in cls) {
            // student的逻辑
        }
    }
    
    function startCourse(cls: Class) {
        if (cls intanceof Teacher) {
            // teacher的逻辑
        }
        if (cls intanceof Student) {
            // student的逻辑
        }
    }

    function startCourse(name: string, score: string | number) {
        if (typeof score === 'number') {
            // teacher的逻辑
        }
        if (typeof score === 'string') {
            // student的逻辑
        }
    }

六、TS进阶

1. 泛型 - 重用
    function startClass<T, U>(name: T, score: U): T {
        return name + score;
    }
    console.log(startClass<string, number>('yy', 5))
    function startClass<T, U>(name: T, score: U): string {
        return `${name}${score}`;
    }

    function startClass<T, U>(name: T, score: U): T {
        return (name + String(score)) as any as T;
    }

    // T U K 键值 |  V 值 | E 节点
2. 装饰器 - decorator
    function Yunyin(target: Function): void {
        target.prototype.startClass = function(): void {
            // start逻辑
        }
    }

    // 类装饰器
    @Yunyin
    class Course {
        constructor() {
            // 业务逻辑
        }
    }

    // 属性装饰器
    function nameWrapper(target: any, key: string) {
        // 逻辑处理
        Object.defineProperty(target, key, {
            // 劫持
        });
    }
    class Course {
        constructor() {
            // 业务逻辑
        }

        @nameWrapper
        public name: string;
    }

    // 方法装饰器
3. 原理解析
    // 1. 源码输入
    let a: number = 2;
    // 2. scanner扫描器扫描 => 识别内容范围生成数据流
    [
        "let": "keyword",
        "a": "identifier",
        "=": "assignment",
        "2": "integer",
        ";": "eos" (end of statement)
    ]
    // number

    // 3. 解析器 parser 生成语法树 - AST
    {
        operation: "=",
        left: {
            keyword: 'var',
            // ...
        }
    }

    // 4. 绑定器 binder 主要职责 创建symbols
    // node.symbol

    // 5. 校验器 checker 检查TS语法错误 => 检查器中进行的

    // 6. 发射器 emitter根据每个节点的检查结果产出node翻译成js

TS常用的工具类型

  1. Partial:构造一个类型,将T的所有属性设置为可选。
// 内部实现原理
type Partial<T> = {
    [K in keyof T]?: T[K]
}
// 通常使用
interface defaultOpt {
		uuid: string | void 0 ;
		requestUrl: string | void 0 ;
}

type pluginOps = Partial<defaultOpt >;

//继承使用
export interface initOptions extends Partial<DefaultOptons> {
  requestUrl: string;
}
  1. Require:将类型T所有属性设为require。
    这个就和上面的是相反的,都变为必填
type Require<T> = {
    [P in keyof T]-?: T[P];
}
  1. Readonly:构造一个类型,将T的所有属性设置为只读。
type Readonly<T> = {
    readonly [K in keyof T]: T[K];
}
  1. Record<K, T>:构造一个对象类型,其属性键为K,属性值为T。
//内部实现原理
type Record<K extends keyof any, T> = {
   [P in K]: T; 
}
// 解释一下
type a = {
	title: string;
	}
type b = 'uuid' | 'requestUrl' | 'name' ;
type c = Record<b,a>;

// 达成的效果就是
type c = {
	uuid:{
		title: string ;
	};
	requestUrl:{
		title: string ;
	};
	name:{
		title: string ;
	}
}

  1. Pick<T, K>:从T中选择一组属性K来构造一个新的类型。
// 内部实现原理
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
}
// 解释一下
type a = {
	uuid: string ;
	requestUrl?:string ;
	name:string;
	}
type b = Record<a,'uuid' | 'name'>;

// 达成的效果就是
type b = {
	uuid: string ;
	name:string;
}
  1. Omit<T, K>:从T中剔除一组属性K来构造一个新的类型。
// 实现原理
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>

// 解释一下
interface Todo {
    uuid: string ;
	requestUrl?:string ;
	name?:string;
}
type T1 = Omit<Todo, 'uuid'>
// 达成的效果
type T1 = {
    requestUrl?:string ;
	name?:string;
}

  1. Exclude<T, U>:从T中剔除所有可以赋值给U的元素类型。
// 内部实现原理
type Exclude<T, U> = T extends U ? never : T;

// 简单演示一下
type T = 'a' | 'b' | 'c';
type U = 'a' | 'b';

// 使用 Exclude 工具类型
type Excluded = Exclude<T, U>;

// 结果是 'c',因为 'a' 和 'b' 都可以赋值给 U,所以被排除掉了
const value: Excluded = 'c';

// 稍微复杂的演示
type P = number | string | (()=>void)
type L = Function

type PL = Exclude<P,L>
// 达成的效果
type PL = number | string ;
// 就是说P是完整的一个类型,L是指要从P中删除掉的类型
  1. Extract<T, U>:提取T中可以赋值给U的所有元素类型。
//实现原理
type Extract<T, U> = T extends U ? T : never;

// 简单演示一下
type T = 'a' | 'b' | 'c' | 'd';
type U = 'a' | 'c' | 'f';

// 使用 Extract 工具类型
type Extracted = Extract<T, U>;

// 结果是 'a' | 'c',因为只有 'a' 和 'c' 可以赋值给 U
const value1: Extracted = 'a';
const value2: Extracted = 'c';
// const value3: Extracted = 'b'; // 错误,'b' 不能赋值给 U

// 说白了,就是找两个类型的交集
  1. NonNullable:从T中剔除null和undefined。
type NonNullable<T> = T extends undefined | null ? never : T;

type T = string | number | null | undefined;

// 使用 NonNullable 工具类型
type NonNullableType = NonNullable<T>;

// 结果是 string | number,因为 null 和 undefined 被剔除了
const value1: NonNullableType = 'hello';
const value2: NonNullableType = 42;
// const value3: NonNullableType = null; // 错误,null 被剔除了
// const value4: NonNullableType = undefined; // 错误,undefined 被剔除了

  1. ReturnType:获取函数类型T的返回类型。
function add(a: number, b: number): number {
  return a + b;
}

// 使用 ReturnType 工具类型
type AddReturnType = ReturnType<typeof add>;

// 结果是 number,因为 add 函数的返回类型是 number
const result: AddReturnType = add(1, 2);
  1. InstanceType:获取构造函数类型T的实例类型。
type InstanceType<T extends new (...args: any[]) => any> = T extends new (...args: any[]) => infer R ? R : any;

// 举个栗子
class MyClass {
  constructor(public name: string) {}
}

// 使用 InstanceType 工具类型
type MyInstanceType = InstanceType<typeof MyClass>;

// 结果是 MyClass,因为 MyClass 的实例类型是 MyClass
const instance: MyInstanceType = new MyClass('example');

还看到了关于instanceType比较深层次的解释,类的值类二象性,不过多赘述了,等我学明白了再讲讲

  • 22
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值