Typescript常见写法

TypeScript 常见写法

了解了ts的一些属性, 通过代码来更加熟悉.

  1. class写法

    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    type skillMap = {
    [key: string]: Skill
    }


    class Hero {

    public name: string

    public bloodVolume: number

    /*** 该参数可缺省 ***/
    public magic?: number

    /*** 如果下面这个属性没有undefined类型就会报错, 因为它在constructor中没有初始化 ***/
    public sex: string | undefined

    /*** 下面使用!的写法表示断言, ts编译器不再对这个变量类型做检查 ***/
    public activeSkills!: skillMap

    constructor(name_: string, bloodVolume_: number, activeSkills_: skillMap, magic_?: number) {
    this.name = name_;
    this.bloodVolume = bloodVolume_;
    this.activeSkills = activeSkills_;
    this.magic = magic_ || 0;
    }

    /*** void可不写, 但是写了会更规范 ***/
    public attack = (enemy: Hero, skill: string): void => {
    this.activeSkills[skill].trigger(this, enemy)
    }

    }

    class Skill {
    /*** 在构造器里对参数添加public修饰符, 在new新实例的时候, 就等同于将他们赋值给了对应名称的属性 ***/
    constructor(
    public name: string,
    public harm: number,
    public cost: number
    ) { }

    public trigger = (caster: Hero, target: Hero) => {
    if (caster.magic) {
    caster.magic -= this.cost;
    }
    target.bloodVolume -= this.harm;
    }

    }

    (() => {
    const jean = new Hero(
    '狙击手杰恩',
    100,
    {
    flyBullet: new Skill('让子弹飞', 20, 0),
    transForm: new Skill('致命一击', 70, 40),
    },
    50
    )

    const jack = new Hero(
    '剪刀手杰克',
    120,
    {
    cutOff: new Skill('风中残叶', 30, 10),
    thorn: new Skill('千疮百孔', 40, 15),
    }
    )
    jack.attack(jean, 'cutOff');

    console.log("***jean***")
    console.log(jean);
    })();
  2. function

    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    /*** 函数重载可以提供代码提示, 使代码结构分明, 自动提示方法和属性 ***/

    /*** type关键字相当于给ts添加诸如 string number一样的新类型 ***/
    type MessageType = 'audio' | 'image'
    type Message = {
    id: number,
    type: MessageType,
    desc: string,
    [key: string]: any
    }

    const MessageRecord: Message[] = [
    {
    id: 1,
    type: 'audio',
    desc: "呼叫二蛋, 晚上五黑, over.",
    dsds:''
    },
    {
    id: 2,
    type: 'image',
    desc: "[🐶].jpg"
    },
    {
    id: 3,
    type: 'image',
    desc: "[🙄].jpg"
    },
    {
    id: 4,
    type: 'audio',
    desc: "呼叫二蛋, 晚上五黑, over."
    },
    {
    id: 5,
    type: 'image',
    desc: "[😡].jpg"
    }
    ]


    function noReloadFunc(): void {
    /*** ts没有办法根据运行之前传递的值, 来判推到方法最终返回的值类型 ***/
    // 只能根据方法定义的类型展现
    function getMess(value: number | MessageType): Message | Array<Message> | undefined {
    if (typeof value === 'number') {
    return MessageRecord.find((msg) => value === msg.id)
    } else {
    return MessageRecord.filter(msg => value === msg.type)
    }
    }

    // 断言 <Message>
    let mess = getMess(2);
    console.log("****普通函数****");
    console.log(mess);
    console.log("******************\n");
    }


    function reloadFunc(): void {
    /*** 函数重载: 一个实现函数签名和一至多个的重载函数签名 ***/
    // 签名函数, 只需要一个实现函数体, 实现签名只是在定义时起到统领所有重载签名的作用, 在执行调用的时候就不看不到实现签名了
    // 实现签名必须兼容所有的重载签名该位置的参数类型(联合类型或者any或者unknown中的一种).
    function getMessage(id: number): Message
    function getMessage(type: MessageType, readCount?: number): Message[]
    // function getMessage(value: any, count?: number): Message | Message[] | undefined {
    function getMessage(value: any, count?: number) {
    if (typeof value === 'number') {
    return MessageRecord.find((msg) => value === msg.id)
    } else {
    return MessageRecord.filter(msg => value === msg.type).splice(0, count || 0)
    }
    }

    // 函数在调用时, 根据参数类型
    let msg = getMessage(2);
    console.log("****第一个重载函数****");
    console.log(msg);
    console.log("******************\n");

    let msgAry = getMessage('image', 3);
    console.log("****第二个重载函数****");
    msgAry.forEach(item => console.log(item));
    console.log("******************\n");
    }

    // noReloadFunc();
    reloadFunc();
  3. arrayList

    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
    67
    /*** 构造函数重载和方法重载 ***/ 

    type obj = {
    id: number,
    value: string,
    [key: string]: any
    }

    class SkillList {
    public elements: obj[] = []

    /*** 构造函数重载 ***/
    constructor(element: obj[])
    constructor(first: obj, second: obj)
    constructor(element: any, secondParam?: any) {
    if (Object.prototype.toString.call(element) === '[object Array]') {
    this.elements = element;
    } else {
    this.elements.concat([element, secondParam]);
    }
    }

    get(index: number) {
    return index < 0 ? this.elements[index] : undefined
    }

    show() {
    this.elements.forEach(item => console.log(item))
    }

    /*** 方法重载 ***/
    remove(target: obj): obj
    remove(target: number): number
    remove(target: any): number | obj {
    this.elements = this.elements.filter((item, index) => {
    if (typeof target === 'number') {
    // 根据索引删除
    return target !== index
    } else {
    // 根据值删除
    return item.id !== target.id && item.value !== target.value
    }
    })
    return target
    }

    }


    (() => {
    const skills = new SkillList([
    { id: 1, value: '斩钢闪' },
    { id: 2, value: '疾风之墙' },
    { id: 3, value: '脚踏斩' },
    { id: 3, value: '狂风绝息斩' },
    ])
    // 构造函数重载
    const passiveSkills = new SkillList(
    { id: 1, value: '点燃' },
    { id: 2, value: '闪现' },
    )
    skills.show();

    // 方法重载
    console.log(skills.remove(2));
    console.log(skills);
    })()
  4. myLocalStorage例子

    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
    /*** 单例模式来熟悉静态方法和静态属性 ***/

    class MyLocalStorage {
    static instance: MyLocalStorage // 存储唯一实例的静态属性
    static already: boolean = false // 是否已初始化

    constructor() {
    // 未曾初始化
    if (!MyLocalStorage.already) {
    return MyLocalStorage.getInstance()
    }
    // 返回已创建实例
    if (MyLocalStorage.instance instanceof MyLocalStorage) {
    return MyLocalStorage.instance
    }
    }

    // 静态方法与实例无关,外部的对象变量不能调用静态属性和静态方法,只能直接通过类名调用
    static getInstance() {
    // 在静态方法中可以使用this来访问静态属性
    // 静态方法不可以访问实例方法和实例属性
    if (!this.already) {
    // 初始化
    this.already = true;
    this.instance = new MyLocalStorage();
    }
    return this.instance
    }

    setItem(key: string, value: any) {
    localStorage.setItem(key, value);
    }

    getItem(key: string) {
    let value = localStorage.getItem(key);
    return value != null ? JSON.parse(value) : null
    }
    }

    /*** ts不允许new类中的方法 ***/
    // var c = new MyLocalStorage.getInstance();

    /*** ts不允许为类的原型添加方法,但是可以重写和调用已实现的方法 ***/
    // MyLocalStorage.prototype.test = ()=>{}


    (() => {
    var a = new MyLocalStorage();
    var b = new MyLocalStorage();
    console.log(a === b);

    var c = MyLocalStorage.getInstance();
    console.log(b === c);
    })()
  5. extends用法

    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    /*** 继承的好处是代码复用,低耦合,代码结构更清晰 ***/

    // 父类:Vechile 交通工具
    class Vechile {
    static count: number = 10; //剩余数量
    public brand: string; // 品牌
    public vechileNo: string; // 车牌号
    public days: number; // 租赁天数
    public total: number = 0; // 支付的租赁总费用
    public deposit: number; // 押金
    constructor(brand_: string, vechileNo_: string, days_: number, deposit_: number) {
    this.brand = brand_;
    this.vechileNo = vechileNo_;
    this.days = days_;
    this.deposit = deposit_;
    }

    // 计算租赁车的价格 ( calculateRent)
    public calculateRent(eg: Vechile) {
    eg
    console.log(this.brand + " 车牌号为:" + this.vechileNo + "开始被租");
    return 0;
    }

    //支付押金的方法( payDesposit)
    payDesposit() {
    console.log(this.brand + " 车牌号为:" + this.vechileNo + " 支付了:" + this.deposit);
    }

    static calcCount(num: number) {
    this.count += num;
    }

    }

    // 子类Car类 独有属性为type_
    class Car extends Vechile {
    public type: string; //车的型号
    constructor(
    brand_: string,
    vechileNo_: string,
    days_: number,
    deposit_: number,
    type_: string,
    count_: number = 1
    ) {
    super(brand_, vechileNo_, days_, deposit_);
    Vechile.calcCount.call(Vechile, -count_)
    this.type = type_;

    }

    // 根据车的型号来获取租用一天该型号车的租金
    public getPriceByType() {
    let rentMoneyByDay: number = 0;//每天的租金
    if (this.type === "普拉多巡洋舰") {
    rentMoneyByDay = 800;
    } else if (this.type === "凯美瑞旗舰版") {
    rentMoneyByDay = 400;
    } else if (this.type === "威驰智行版") {
    rentMoneyByDay = 200;
    }
    return rentMoneyByDay;
    }

    // private 是私有的访问修饰符 只允许在本类中访问
    // protected 是受保护的访问修饰符【修饰符是用来控制方法或属性访问的范围】 可以被本类和子类中使用,不能在类的外部使用
    // public 可以被本类和子类中使用,也可以在类的外部使用
    public calculateRent(eg: Car) {//方法重写 [override]
    super.calculateRent(eg); //=Vechile.prototype.calculateRent.call(this)
    console.log("车行剩余可租:", Car.count);
    return this.days * this.getPriceByType();
    }

    // 默认是public
    checkIsWeigui(isOverWeight: boolean) {
    if (isOverWeight) {
    this.total = this.total + 500;
    }
    }
    }

    let car = new Car("普拉多", "京3A556", 3, 100000, "凯美瑞旗舰版", 2);
    // console.log("租车费用为:" + car.calculateRent(car));


    class Bus extends Vechile {
    public seatNum: number // 座位数
    constructor(
    brand_: string,
    vechileNo_: string,
    days_: number,
    deposit_: number,
    seatNum_: number,
    count_: number = 1
    ) {
    // Vechile.call(this,brand_, vechileNo_, days_, total_, deposit_)
    Vechile.calcCount.call(Vechile, -count_)
    super(brand_, vechileNo_, days_, deposit_);//使用父类的构造函数的好处
    this.seatNum = seatNum_;
    if (this.seatNum > 200) {
    throw new Error("座位数不能超过200");
    }
    }

    public getPriceBySeatNum() { //计算租赁价格
    let rentMoneyByDay: number = 0;//每天的租金
    if (this.seatNum <= 16) {
    rentMoneyByDay = 800;
    } else if (this.seatNum > 16) {
    rentMoneyByDay = 1600;
    }
    return rentMoneyByDay;
    }

    // 重写父类方法的时,父类方法的访问范围必须大于子类方法重写的访问范围
    // 重写父类方法参数类型可以是父子继承关系,any,unknown,或者引用数据类型(如父为number[]、子为string[]);但不能是不同的基本数据类型(父为number、子为string)
    public calculateRent(eg: Vechile) {
    super.calculateRent(eg);
    return this.days * this.getPriceBySeatNum();
    }

    checkIsOverNum(isOverWeight: boolean) {
    if (isOverWeight) {
    this.total = this.total + 2000;
    }
    }
    }

    class Truck extends Vechile {
    ton!: number // 座位数
    constructor(brand_: string, type_: string,
    days_: number, deposit_: number, ton_: number) {
    super(brand_, type_, days_, deposit_);
    this.ton = ton_;
    if (this.ton < 300 || this.ton > 2000) {
    throw new Error("吨数在300-2000吨之间");
    }
    }

    checkIsOverWeight(isOverWeight: boolean) {
    if (isOverWeight) {
    console.log("超载了");
    this.total = this.total + 2000;
    }
    }

    CalRentPriceByTon() {
    //计算租赁价格
    let rentMoneyByDay: number = 0;
    if (this.ton <= 500) {
    rentMoneyByDay = 750;
    } else if (this.ton > 500) {
    rentMoneyByDay = 1350;
    }
    return rentMoneyByDay;
    }

    // 1.多态的定义:
    // 父类的对象变量可以接受任何一个子类的对象,从而用这个父类的对象变量来调用子类中重写的方法而输出不同的结果.
    // 2.产生多态的条件:
    // 1.必须存在继承关系 2.必须有方法重写
    // 3.多态的好处:
    // 利于项目的扩展【从局部满足了 开闭原则--对修改关闭,对扩展开放】
    // 4.多态的局限性
    // 无法直接调用子类独有方法,必须结合instanceof类型守卫来解决
    public calculateRent() {
    return this.CalRentPriceByTon() * this.days;
    }

    }


    class Customer {
    rentVechile(vechile: Vechile) {
    if (vechile instanceof Car) {
    vechile.checkIsWeigui(true);
    } else if (vechile instanceof Bus) {
    vechile.checkIsOverNum(true);
    } else if (vechile instanceof Truck) {
    vechile.checkIsOverWeight(true)
    }
    return vechile.calculateRent(vechile);
    }
    }

    const zhixuan = new Customer();
    console.log("费用:" + zhixuan.rentVechile(car));
  6. 类型断言

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /*** 
    * 类型断言中的不能相互重叠问题:
    * 两个类之间断言的规则:
    * 两个类中任意一个的属性和方法是另一个类的属性和方法完全相同或子集,则这两个类可以相互断言
    * 否则这两个类就不能相互断言
    ***/
    class Person {
    public duty!: string
    }

    class Cooker extends Person {
    public age!: string
    }

    const cooker = new Person();

    // 类型断言的两种方式
    let target = <Cooker>cooker;
    let target2 = cooker as Cooker;
  7. 抽象用法

    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    /***
    * 抽象类并不能进行实例化
    * 它规范了继承它的子类必须拥有抽象属性与抽象方法
    * 它提供了抽象属性与抽象方法来让继承它的子类重写,来实现不同的处理方式
    * 它的保护属性与方法可以被每个子类继承来实现继承子类的公有部分,这部分方法属性处理的是相同的任务
    * 它类似于一个工厂,每个子类都可以去它那里继承公有的部分,但是也必须拥有它私有的部分,每个继承的子类都有相似的部分,又有它们独特的部分
    */

    abstract class People {
    public name!: string
    //抽象方法 特点 1:没有方法体 2:带abstract关键字
    abstract eat(): void

    public step() {
    console.log("双腿走路");
    }
    }

    class AmericanPeople extends People {
    eat(): void {
    throw new Error('Method not implemented.');
    }

    public phone!: string

    }


    class ChinesePeople extends People { //中国人
    public eat() {
    console.log("用筷子吃饭...");
    }
    }

    class TuzhuPeople extends People { // 土族人
    public eat() {
    console.log("用手抓吃饭...");
    }
    }

    let people: People = new AmericanPeople();

    console.log(people.step());


    // 抽象类的一些用法
    interface MouseListenerProcess {
    mouseReleased(e: any): void// 鼠标按钮在组件上释放时调用。
    mousePressed(e: any): void// 鼠标按键在组件上按下时调用。
    mouseEntered(e: any): void //鼠标进入到组件上时调用。

    mouseClicked(e: any): void// 鼠标按键在组件上单击(按下并释放)时调用。
    mouseExited(e: any): void// 鼠标离开组件时调用。
    }

    abstract class MouseListenerProcessAdapter implements MouseListenerProcess {
    mouseReleased(e: any): void {
    throw new Error("Method not implemented.");
    }
    mousePressed(e: any): void {
    throw new Error("Method not implemented.");
    }
    mouseEntered(e: any): void {
    throw new Error("Method not implemented.");
    }
    mouseClicked(e: any): void {
    throw new Error("Method not implemented.");
    }
    mouseExited(e: any): void {
    throw new Error("Method not implemented.");
    }

    }

    class MyMouseListenerProcess extends MouseListenerProcessAdapter {

    mouseClicked(e: any): void {
    throw new Error('Method not implemented.');
    }

    mouseExited(e: any): void {
    throw new Error('Method not implemented.');
    }

    }
  8. 自定义守卫

    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
    /***
    * 自定义守卫
    * function 函数名(形参: 参数类型【参数类型大多为any】):形参 is A类型 {
    * return true or false
    * }
    ***/

    type Btn = {
    onclick: () => void
    }

    type Img = {
    src: string
    }


    function isButton(e: Btn | Img): e is Btn {
    return (e as Btn).onclick !== undefined
    }

    function handleElement(e: Btn | Img) {
    if (isButton(e)) {
    e;
    } else {
    e;
    }
    }



    const arr = [10, 30, 40, "abc"] as const
    // arr[0] = 100; //错误 无法分配到 "数组的索引为0位置的元素" ,因为它是只读属性

    function showArr(arr: readonly any[]) {//类型“readonly any[]”中的索引签名仅允许读取。
    //arr[0] = 100;
    console.log(arr)
    }


    // 元组标签
    let [username, age, ...rest]: [name_: string, age_: number, ...rest: any[]] = ["土豆", 23,
    "海口海淀岛四东路3号", "133123333", "一路同行,一起飞", 23, "df"]
    console.log("username:", username) //土豆
    console.log("age:", age) //23
    console.log("rest:", rest)
  9. 泛型

    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
    // 泛型的作用 就是增强类的实现范围
    // 泛型定义时不指定类型,使用时必须明确的数据类型
    // 编译期间会进行数据安全检查的数据类型(这就是使用它与使用any、object的区别之处)
    // 泛型可使用的字母:A-Z

    class ArrayList<T>{
    public elements: Array<T> = []

    add(val: T) {
    this.elements.push(val)
    }

    get(index: number): T {
    return this.elements[index]
    }

    remove(target: T) {
    this.elements = this.elements.filter(i => JSON.stringify(i) !== JSON.stringify(target))
    }

    }

    var stringAry = new ArrayList<string>();
    stringAry.add("");


    type Student = { name: string, age: number };

    class Performer {
    constructor(public name: string, public creation: string, public interest: string) { }

    sing() { }
    }

    let performer = new Performer('古天乐', '门徒', '晒黑');
    let singer: Student = { name: '张学友', age: 18 };
    let singer2 = { name: '周杰伦', creation: '', interest: '', sing: () => { } };

    var sanNian1Ban = new ArrayList<typeof performer>();
    var sanNian2Ban = new ArrayList<typeof singer>();
    var sanNian3Ban = new ArrayList<Performer>();

    sanNian1Ban.add(performer); // add方法接受的参数类型 { name: string; age: number; }
    sanNian2Ban.add(singer); // add方法接受的参数类型 Student
    sanNian3Ban.add(singer2); // add方法接受的参数类型 Performer

    console.log(sanNian1Ban.get(0))
    console.log(sanNian2Ban.get(0))
  1. 泛型约束
    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
    // 泛型约束

    /*** T extends object 把泛型的具体化数据类型范围缩小 ***/

    class ContentBox<T extends object> {
    t!: T;
    show() {
    console.log(this.t)
    }
    }

    type test_object = { test: string };

    class TestObject { };

    let box = new ContentBox<test_object>()
    let box2 = new ContentBox<TestObject>()
    // let box3 = new ContentBox<string>() // string不属于object类型的子类
    let box3 = new ContentBox<String>() // String类属于object



    /*** keyof表示获取一个类、一个对象类型或一个接口类型的所有属性名组成的联合类型 ***/

    class ContentBox2<T extends object, K extends keyof T> { }

    let obj = { orderList: [], orderCount: 0, orderPrice: 0 }
    type myobjtype = typeof obj;
    type keyofobj = keyof myobjtype;
    let key:keyofobj = "orderCount"
  1. 泛型接口和泛型类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    interface List<T> {
    add(elel: T): void;
    get(index: number): T;
    size(): number;
    remove(value: T): T;
    }


    class LinkedList implements List<string> {
    add(elel: string): void {
    throw new Error("Method not implemented.");
    }
    get(index: number): string {
    throw new Error("Method not implemented.");
    }
    size(): number {
    throw new Error("Method not implemented.");
    }
    remove(value: string): string {
    throw new Error("Method not implemented.");
    }

    }
  2. 交叉属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // 交叉属性的定义: 将多个类型合并【多个类型属性和方法的并集】成的类型就是交叉类型

    type obj1 = { width: number, height: number }
    type obj2 = { area: number, unit: string }
    type obj3 = { round: number, unit: string }

    // 需要实现obj1和obj2的全部类型
    let box: obj1 & obj2 = {
    width: 0,
    height: 0,
    area: 0,
    unit: "m",
    }

    // 需要实现obj1和obj2的其中只一个或者全部类型
    let unit: obj2 | obj3 = {
    area: 0,
    unit: "m",
    round: 0
    }
  3. 泛型与infer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // infer只允许出现在extends语句当中

    interface Customer {
    custName: string
    buymoney: number
    }


    type custFuncType = (cust: Customer) => string

    // infer相当于占位符
    type inferType<T> = T extends (param: infer P) => any ? P : string
    type inferResultType = inferType<custFuncType>


    type inferType2<T> = T extends (param: any) => infer P ? P : T
    type inferResultType2 = inferType2<custFuncType>
  4. 泛型函数重载

    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
    67
    68
    interface combineObj {
    [key: string]: string
    }

    interface Button {
    btnType: string
    text: string
    }

    interface Link {
    alt: string
    href: string
    }

    interface Href {
    linkType: string
    target: OpenLocation
    }

    enum OpenLocation {
    self = 'self',
    _blank = '_blank',
    parent = 'parent'
    }

    let button: Button = {
    btnType: 'normal',
    text: 'clicked'
    }

    let link: Link = {
    alt: '网易云音乐',
    href: 'https://music.163.com/'
    }

    let href: Href = {
    linkType: '外网',
    target: OpenLocation._blank
    }


    // type Extract<T, U> = T extends U? T: never
    type checkIsObject<T> = Extract<T, object> // 如果T为object类型的子类, 就是返回T,否则返回never

    function unity<T, U>(objOne: checkIsObject<T>, objTwo: checkIsObject<U>): T | U
    function unity<T, U, V>(objOne: checkIsObject<T>, objTwo: checkIsObject<U>, objThree: checkIsObject<V>): T | U | V
    function unity<T, U, V>(objOne: checkIsObject<T>, objTwo: checkIsObject<U>, objThree?: checkIsObject<V>) {
    let obj = {}
    let combine = obj as combineObj
    let arr: (T | U | V)[] = [objOne, objTwo]

    if (objThree) {
    arr = [objOne, objTwo, objThree]
    }

    arr.forEach((obj: any) => {
    Object.keys(obj).forEach((key) => {
    if (!combine.hasOwnProperty(key)) {
    combine[key] = obj[key]
    }
    })
    })

    return combine
    }

    console.log(unity(button, link));
    console.log(unity(button, link, href));
  1. lodash函数库中mapvalues的一个精彩的函数泛型
    1
    mapValues<T extends object, TResult>(obj: T | null | undefined, callback: ObjectIterator<T, TResult>): { [P in keyof T]: TResult };