Wsh's blog Wsh's blog
首页
  • 基础知识
  • ArkUI
  • UIAbility
  • 组件通信方式
  • 前端缓存
  • React
  • typescript
  • javascript
  • flutter
  • node
  • webpack
web3D😉
宝库📰
  • 分类
  • 标签
  • 归档
龙哥的大🐂之路 (opens new window)
GitHub (opens new window)

wsh

热爱前端的程序媛
首页
  • 基础知识
  • ArkUI
  • UIAbility
  • 组件通信方式
  • 前端缓存
  • React
  • typescript
  • javascript
  • flutter
  • node
  • webpack
web3D😉
宝库📰
  • 分类
  • 标签
  • 归档
龙哥的大🐂之路 (opens new window)
GitHub (opens new window)
  • 基础类型
  • 类型断言、类型声明
  • 枚举、函数、类、装饰器
    • 联合类型&交叉类型、泛型、类型保护、类型推断
    • 模块、命名空间
    • tsc 指令,ts配置
    • typescript
    2022-04-14
    目录

    枚举、函数、类、装饰器

    # 枚举: enum

    数字枚举

    enum Status {
        Uploading,
        Success,
        Failed = 8
    }
    
    console.log(Status.Uploading)  // 0
    console.log(Status.Success) // 1
    console.log(Status.Failed) // 8
    
    enum Status {
        Uploading = 3,
        Success,
        Failed = 8
    }
    
    console.log(Status.Uploading)  // 3
    console.log(Status.Success) // 4
    console.log(Status.Failed) // 8
    
    • 如果没有初始化,默认初始化值为0,每项+1
    • 如果有初始化,则在初始化值的基础上,每项+1

    字符串枚举

    • 每个成员必须用字符串文字或其他字符串枚举成员进行常量初始化,否则会报Error:Enum member must have initializer
    enum Status {
        Uploading = 'Uploading',
        Success = 'Success',
        Failed = 'Failed'
    }
    
    console.log(Status.Uploading)
    console.log(Status.Success)
    console.log(Status.Failed)
    

    异构枚举

    • 不建议使用
    enum BooleanLikeHeterogeneousEnum {
        No = 0,
        Yes = "YES",
    }
    

    反向映射

    • 一个枚举被编译成一个存储forward(name- > value)和reverse(value- > name)映射的对象
    enum Enum {
        A
      }
    const a = Enum.A; // 0
    const nameOfA = Enum[a]; // "A"
    
     <!-- var Enum;
    (function (Enum) {
      Enum[Enum["A"] = 0] = "A";
    })(Enum || (Enum = {})); -->
    
    

    常数枚举

    const enum Directions {
        Up,
        Down,
        Left,
        Right
    }
    
    const directions = [Directions.Up, Directions.Down, Directions.Left, Directions.Right];
    console.log(directions)
    <!--会被编译成 var directions = [0 /* Up */, 1 /* Down */, 2 /* Left */, 3 /* Right */]; -->
    

    # 函数

    可以声明具名函数和匿名函数

    function fn(x) { // 名字为b的函数
      return x;
    }
    const fn1 = function (x) { // 没有名字的函数声明,直接将函数值赋给变量b1
      return x;
    }
    

    函数的类型包含参数类型和返回值类型两个部分. 可选参数名必需放在必传的参数后面

    - this
    
    返回一个函数:
    

    const fn2: (y: number) => number = function (x: number): number { return x; }

    
    const b14 = {
      m1: 1,
      m2: function (): () => void { // 返回一个函数
        return function (): void {
          console.log(this.m1);
        };
      },
    }
    
    b14.m2()(); // 打印:undefined
    

    这里的this是window对象(如果是严格模式的话,this为undefined),因为返回一个函数再执行,相当于在顶层作用域下执行:

    function (): void {
      console.log(this.m1); // 打印:undefined
    };
    

    解决方案: 使用箭头函数解决这个问题,因为箭头函数捕获函数创建时候的this而不是函数调用时的this。

    const b14 = {
      m1: 1,
      m2: function (): () => void { // 返回一个函数
        return (): void => {
          console.log(this.m1);
        };
      },
    }
    b14.m2()(); // 打印:1
    
    // 这里的this就是函数创建时候的this,即b14对象
    

    传递一个函数作为参数: 打开noImplicitThis配置,在使用隐含any类型的this的时候会报错。打开noImplicitThis配置之后,下面这段代码,this的位置会报错:

    const b15 = {
      m1: 1,
      m2: function (x: () => void): void { // 将函数作为一个参数
        x();
      },
    };
    
    const b16 = function (): void {
      console.log(this.m1);
    }
    
    b15.m2(b16); // 打印:undefined
    

    # 类

    • 类可以从基类继承属性和方法。
    • public、private、protected是类成员的三个修饰符。分别表示公有成员、私有成员、被保护的成员。
    • TypeScript 3.8 带来了私有字段,私有字段以#符号开头
    • 每个私有字段名称都唯一地作用于其包含的类。
    • 【private修饰符修饰的私有成员】和【前面加上#表示的私有字段】都只能在包含它们的类中被访问。前者能修饰方法和属性,后者只能表示属性不能表示方法。
    • protected成员不能被派生类的实例访问
    • 构造函数被标记为protected,这意味着这个类不能在包含它的类外面被实例化,但是可以被扩展.
    class C11 {
      protected m1: number = 123;
    }
    
    class C12 extends C11 {
      m2(): void {
        console.log(this.m1);
      }
    }
    
    const c12 = new C12();
    c12.m2(); // 打印:123
    c12.m1; // 报错:属性“m1”受保护,只能在类“C11”及其子类中访问.
    
    class C13 {
      m1: number;
      protected constructor(x) {
        this.m1 = x;
      }
    }
    
    class C14 extends C13 {
      constructor(x) {
        super(x);
      }
    }
    
    const c13 = new C13(1); // 报错:类“C13”的构造函数是受保护的,仅可在类声明中访问
    const c14 = new C14(1);
    console.log(c14.m1); // 打印:1
    

    # 装饰器 @

    • 每个装饰器的表达式从上到下进行评估,然后结果被称为从下到上的函数。
    function setName() {
        console.log('get setName');
        return (target: any) => {
            console.log(target, 'setName');
        }
    }
    function setAge() {
        console.log('get setAge');
        return (target: any) => {
            console.log(target, 'setAge');
        }
    }
    
    @setName()
    @setAge()
    
    // 执行结果为
    // get setName
    // get setAge
    // setAge
    // setAge
    

    # 类装饰器

    function addName(constructor: new() => any) {
        constructor.prototype.name = 'liston';
    }
    @addName
    class ClassD {}
    interface ClassD {
        name: string
    }
    // 接口添加到 类的原型对象上,注意:interface需要在class 之后添加
    const d = new ClassD();
    console.log(d, 'ClassD')
    console.log(d.name)
    

    # 方法装饰器

    在一个方法声明前被声明,装饰器应用到方法的属性描述符上,并且可以用来观察、修改、或者替代一个方法定义。一个方法装饰器不能被用在声明文件中、重载中、或者在任何环境上下文(比如declare类)中 方法装饰器的表达式在运行时作为一个函数调用,包含三个参数:

    1. target:对于静态成员,是类的构造函数;对于实例成员,是类的原型(prototype)。
    2. propertyKey:成员的名称。
    3. descriptor:成员的属性描述符。(注意:属性描述符在你的脚本目标小于ES5的时候会是undefined)

    属性描述符:

    interface PropertyDescriptor {
        configurable?: boolean;
        enumerable?: boolean;
        value?: any;
        writable?: boolean;
        get?(): any;
        set?(v: any): void;
    }
    
    class C26 {
      @writable(false)
      m1() {
        console.log("aaa");
      }
    }
    
    function writable(x: boolean) {
      return function (
        target: any,
        propertyKey: string,
        descriptor: PropertyDescriptor
      ) {
        return {
          writable: false,
        };
      };
    }
    
    const c26 = new C26();
    c26.m1 = () => {
      console.log("bbb");
    };
    // ERROR: decorators.ts:123 Uncaught TypeError: Cannot assign to read only property 'm1' of object '#<C26>'...
    

    # 存取器装饰器

    • 存取器装饰器应用在存取器的属性描述符

    注意:

    TypeScript不允许同时装饰成员的get和set存取器。该成员的所有装饰器必须应用到文档顺序的第一个存取器。这是因为装饰器应用于属性描述符,属性描述符将get和set存取器组合在一起,而不是分开声明。否则会报Error:Decorators cannot be applied to multiple get/set accessors of the same name

    # 属性装饰器

    • 属性装饰器在一个属性声明前声明。一个属性装饰器不能用在一个声明文件中,或者任何其他的环境上下文(比如一个declare类)中
    • 属性装饰器的表达式会作为一个函数在运行时被调用,使用以下两个参数:

    1.target: 对于静态成员来说是类的构造函数,对于实例成员来说是类的原型。

    2.propertyKey: 成员的名字。

    注意:

    因为TypeScript中初始化属性装饰器的机制,一个属性描述符不能用作一个属性装饰器的参数。这是因为目前当定义原型的成员的时候,没有机制来描述一个实例属性,并且没有办法来观察或者修改属性的初始化。返回值也被忽视了。因此,一个属性装饰器只能用来观察类中已经明确声明了一个名字的属性

    # 参数装饰器(babel 暂不支持)

    参数装饰器在参数声明前被声明。参数装饰器应用于类的构造函数声明或方法声明。参数装饰器不能用在声明文件中、重载中、或者在任何其他环境上下文(比如一个declare类)中。

    参数装饰器的会作为函数在运行时被调用,带着以下三个参数

    1. target: 对于静态成员,是类的构造函数;对于实例成员,是类的原型(prototype)。
    2. propertyKey: 成员的名称。
    3. parameterIndex: 函数的参数列表中参数的序号索引。
    class C29 {
      m1 (@decoratorC29 x: number) {
        console.log(x);
      }
    
      m2 () {
        console.log('456');
      }
    }
    
    function decoratorC29 (
      target: any,
      propertyKey: string | symbol,
      parameterIndex: number
    ) {
      target.m2();
    }
    
    #typescript
    类型断言、类型声明
    联合类型&交叉类型、泛型、类型保护、类型推断

    ← 类型断言、类型声明 联合类型&交叉类型、泛型、类型保护、类型推断→

    最近更新
    01
    组件通信方式
    01-07
    02
    UIAbility
    01-07
    03
    ATKTS
    01-06
    更多文章>
    Theme by Vdoing | Copyright © 2022-2025 Wsh | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式