• 【工具篇】高级 TypeScript 案例


    本文说明:TypeScript 相关文章,了解更多特性。
    网页编辑器https://www.typescriptlang.org/zh/play

    TypeScript

    联合类型

    概念:当某个函数只有一个参数,且希望该参数是某个类型或另一个类型时,就采用 联合类型

    案例:检查某个值是否落在特定区间内

    // 检查某个值是否落在特定区间内
    // 接收 string 值 | number 值
    class RangeValidationBase {
        // 目标区间: 最小值 和 最大值
        constructor(private start: number = 0, private end: number = 10) {}
    
        protected RangeCheck(value: number) : boolean {
            return value >= this.start && value <= this.end;
        }
    
        protected GetNumber(value: string) : number {
            return new Number(value).valueOf();
        }
    }
    
    // 只接受 string | number
    class UnionRangeValidation extends RangeValidationBase {
        IsInRange(value: string | number) : boolean {
            if (typeof value === "number") {
                return this.RangeCheck(value);
            }
            return this.RangeCheck(this.GetNumber(value));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    输出结果:

    // const a = new UnionRangeValidation().IsInRange("123");
    [LOG]: false 
    // const a = new UnionRangeValidation().IsInRange("5");
    [LOG]: true 
    
    • 1
    • 2
    • 3
    • 4

    交叉类型

    交叉可以用于类、接口、泛型、基本类型。

    // 将多个类型合并成一个类型
    class Grid {
        Width: number = 0;
        Height: number = 0;
    }
    
    class Margin {
        Top: number = 0;
        Left: number = 0;
    }
    
    // 交叉
    function ConsolidatedGrid(grid: Grid, margin: Margin) : Grid & Margin {
        const consolidatedGrid = Object.assign({}, grid, margin);
        return consolidatedGrid;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    装饰器

    通过不改变原有的类,去增加功能。

    对于要使用装饰器,请开启 experimentalDecorators ,设置为 true 。

    原始类:

    interface IDecoratorExample {
        AnyoneCanRun(args: string): void;
        AdminOnly(args: string):  void;
    }
    
    class RoleCheck implements IDecoratorExample {
        AnyoneCanRun(args: string): void {
            console.log(args);
        }
        AdminOnly(args: string): void {
            console.log(args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    输出结果:

    // new RoleCheck().AnyoneCanRun("Jemmy as user can running.");
    Jemmy as user can running.
    // new RoleCheck().AdminOnly("Jemmy as Admin can running.")
    Jemmy as Admin can running.
    
    • 1
    • 2
    • 3
    • 4

    根据结果展示两个都能运行成功。

    添加装饰器。

    看到类似下面的这行代码,就表明这是一个装饰器。

    function(target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor)

    函数说明:

    • target 表明目标元素
    • propertyKey 目标元素属性名
    • descriptor 装饰器
    function isInRole(role: string): boolean {
        return user2.roles.some(r => r === role);
    }
    
    // 装饰器
    function Role(role: string) {
        return function(target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
            let originalMethod = descriptor.value;
            descriptor.value = function() {
                if (isInRole(role)) {
                    originalMethod.apply(this, arguments);
                    return ;
                }
                console.log(`${user2.user} is not in the ${role} role`);
            }
            return descriptor;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后通过 @Role() 添加到需要装饰的函数上面。

    @Role("user")
    AnyoneCanRun(args: string): void {
        console.log(args);
    }
    @Role("admin")
    AdminOnly(args: string): void {
        console.log(args);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试结果:

    // const user2 = {user: "Jemmy", roles: ["user"]}
    
    // new RoleCheck().AnyoneCanRun("Jemmy as user can running.");
    Jemmy as user can running
    // new RoleCheck().AdminOnly("Jemmy as Admin can running.")
    Jemmy is not in the admin role
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    混入 mixin

    可以给已存在构造器,添加额外的属性,而不是在原先的基础上修改。
    必要的类型声明:

    type Constructor<T = {}> = new (...args: any[]) => T;
    
    • 1

    根据情况去添加属性,这里以 Deleted 举例。

    function RecordStatus<T extends Constructor >(base: T) {
        return class extends base {
        	// 在这里写属性
            Deleted:  boolean = false;
        }
    }
    
    // 进阶用法: 
    function RecordStatus<T extends Constructor >(base: T) {
        return class extends base {
            deleted: boolean = false;
            
            get Deleted(): boolean {
                return this.deleted;
            }
    
            Delete() : void {
                this.deleted = true;
                console.log("The record has been marked as deleted. ")
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    使用?

    class Personn {
        constructor(private firstName: string, private lastName: string) {}
    }
    
    // 创建一个新的构造器
    const ActivePerson = RecordStatus(Person);
    // 通过新的构造器去创建实例
    let p1 = new ActivePerson("三", "张");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    更多使用方式:可以嵌套。

    其中 Timestame 和 RecordStatus 都是额外添加属性,它们嵌套顺序可以改变。

    const ActivePerson = Timestamp(RecordStatus(Personn))
    
    • 1

    泛型

    这一个知识点很简单,将类型转换成 T 去代替即可。

    class Queue<T> {
        private queue: T[] = [];
    
        push(value: T) : void {
            this.queue.push(value);
        }
    
        pop(): T | undefined {
            return this.queue.shift();
        }
    
        get length() : number {
            return this.queue.length;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    输出结果:

    // const q1 = new Queue();
    // q1.push("1")
    // q..push("2")
    // q1.pop()
    1
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Promise 简单应用

    延时 time 毫秒。

    function ExpensiveWebCall(time: number) : Promise<void> {
        return new Promise((resolve, reject) => setTimeout(resolve, time));
    }
    
    • 1
    • 2
    • 3

    使用?

    console.log("正在处理...")
    ExpensiveWebCall(3000).then(() => {
        console.log("web service end")
    }).catch(() => {
        console.log("appear errors")
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    使用 SSH 密钥进行身份验证
    C编程入门到精通 专辑目录
    从开发到测试再到发布,全方位解析项目上线的完美路程!
    嵌入式系统中偶发性问题
    String为什么是不可变的?
    Ventus(承影):基于RISC V的开源GPGPU
    R语言dist函数计算dataframe数据中两两样本之间的距离返回样本间距离矩阵,通过method参数指定距离计算的方法、例如欧几里得距离
    【个人首测】百度文心一言 VS ChatGPT GPT-4
    【前端每日基础】day34——HTTP和HTTPS
    nmake简介
  • 原文地址:https://blog.csdn.net/qq_56402474/article/details/132916185