zoukankan      html  css  js  c++  java
  • TypeScript“奇怪”的符号

    本文将分享这些年在学习 TypeScript 过程中,遇到的 10 大 “奇怪” 的符号。其中有一些符号,码云笔记第一次见的时候也觉得 “一脸懵逼”,希望本文对学习 TypeScript 的小伙伴能有一些帮助。

    ! 非空断言操作符

    在上下文中当类型检查器无法断定类型时,一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。具体而言,x! 将从 x 值域中排除 null 和 undefined 。

    function myFunc(maybeString: string | undefined | null) {
      const onlyString: string = maybeString; // Error
      const ignoreUndefinedAndNull: string = maybeString!; // Ok
    }
    

    调用函数时忽略 undefined 类型 场景

    type NumGenerator = () => number;
    function myFunc(numGenerator: NumGenerator | undefined) {
      const num1 = numGenerator(); // Error
      const num2 = numGenerator!(); //OK
    }
    

    ?. 运算符

    TypeScript 3.7 实现了呼声最高的 ECMAScript 功能之一:可选链(Optional Chaining)。有了可选链后,我们编写代码时如果遇到 null 或 undefined 就可以立即停止某些表达式的运行。可选链的核心是新的 ?. 运算符

    obj?.prop
    obj?.[expr]
    arr?.[index]
    func?.(args)
    const val = a?.b;
    

    语句编译生成的 ES5 代码:

    var val = a === null || a === void 0 ? void 0 : a.b;
    

    可选链与函数调用

    let result = obj.customMethod?.();
    

    ?? 空值合并运算符

    在 TypeScript 3.7 版本中除了引入了前面介绍的可选链 ?. 之外,也引入了一个新的逻辑运算符 —— 空值合并运算符 ??
    当左侧操作数为 null 或 undefined 时,其返回右侧的操作数,否则返回左侧的操作数。

    const foo = null ?? 'default string';
    console.log(foo); // 输出:"default string"
    

    短路

    不能与 && 或 || 操作符共用

    (null || undefined ) ?? "foo"; // 返回 "foo"
    

    与可选链操作符 ?. 的关系

    空值合并运算符针对 undefined 与 null 这两个值,可选链式操作符 ?. 也是如此。可选链式操作符,对于访问属性可能为 undefined 与 null 的对象时非常有用。

    interface Customer {
      name: string;
      city?: string;
    }
    
    let customer: Customer = {
      name: "Semlinker"
    };
    
    let customerCity = customer?.city ?? "Unknown city";
    console.log(customerCity); // 输出:Unknown city
    

    ?: 可选属性

    在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类去实现。 TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

    & 运算符

    在 TypeScript 中交叉类型是将多个类型合并为一个类型。通过 & 运算符可以将现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。

    type PartialPointX = { x: number; };
    type Point = PartialPointX & { y: number; };
    
    let point: Point = {
      x: 1,
      y: 1
    }
    

    | 分隔符

    在 TypeScript 中联合类型(Union Types)表示取值可以为多种类型中的一种,联合类型使用 | 分隔每个类型。联合类型通常与 null 或 undefined 一起使用:

    const sayHello = (name: string | undefined) => { /* ... */ };
    

    类型保护 in 关键字

    interface Admin {
      name: string;
      privileges: string[];
    }
    
    interface Employee {
      name: string;
      startDate: Date;
    }
    
    type UnknownEmployee = Employee | Admin;
    
    function printEmployeeInformation(emp: UnknownEmployee) {
      console.log("Name: " + emp.name);
      if ("privileges" in emp) {
        console.log("Privileges: " + emp.privileges);
      }
      if ("startDate" in emp) {
        console.log("Start Date: " + emp.startDate);
      }
    }
    

    typeof 关键字

    function padLeft(value: string, padding: string | number) {
      if (typeof padding === "number") {
          return Array(padding + 1).join(" ") + value;
      }
      if (typeof padding === "string") {
          return padding + value;
      }
      throw new Error(`Expected string or number, got '${padding}'.`);
    }
    

    instanceof 关键字

    interface Padder {
      getPaddingString(): string;
    }
    
    class SpaceRepeatingPadder implements Padder {
      constructor(private numSpaces: number) {}
      getPaddingString() {
        return Array(this.numSpaces + 1).join(" ");
      }
    }
    
    class StringPadder implements Padder {
      constructor(private value: string) {}
      getPaddingString() {
        return this.value;
      }
    }
    
    let padder: Padder = new SpaceRepeatingPadder(6);
    
    if (padder instanceof SpaceRepeatingPadder) {
      // padder的类型收窄为 'SpaceRepeatingPadder'
    }
    

    TypeScript 断言 <Type>

    通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。类型断言好比其他语言里的类型转换,但是不进行特殊的数据检查和解构。它没有运行时的影响,只是在编译阶段起作用。

    “尖括号” 语法

    let someValue: any = "this is a string";
    let strLength: number = (<string>someValue).length;
    

    as 语法

    let someValue: any = "this is a string";
    let strLength: number = (someValue as string).length;
    

    TypeScript 泛型

    泛型详解
    参考上面的图片,当我们调用 identity(1) ,Number 类型就像参数 1 一样,它将在出现 T 的任何位置填充该类型。图中 内部的 T 被称为类型变量,它是我们希望传递给 identity 函数的类型占位符,同时它被分配给 value 参数用来代替它的类型:此时 T 充当的是类型,而不是特定的 Number 类型。

    其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替。除了 T 之外,以下是常见泛型变量代表的意思:

    K(Key):表示对象中的键类型;
    V(Value):表示对象中的值类型;
    E(Element):表示元素类型。
    其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。比如我们引入一个新的类型变量 U,用于扩展我们定义的 identity 函数:

    function identity <T, U>(value: T, message: U) : T {
      console.log(message);
      return value;
    }
    
    console.log(identity<Number, string>(68, "Semlinker"));
    

    @XXX 装饰器 装饰器语法

    @Plugin({
      pluginName: 'Device',
      plugin: 'cordova-plugin-device',
      pluginRef: 'device',
      repo: 'https://github.com/apache/cordova-plugin-device',
      platforms: ['Android', 'Browser', 'iOS', 'macOS', 'Windows'],
    })
    @Injectable()
    export class Device extends IonicNativePlugin {}
    

    类装饰器声明:

    declare type ClassDecorator = <TFunction extends Function>(
      target: TFunction
    ) => TFunction | void;
    

    属性装饰器

    declare type PropertyDecorator = (target:Object, 
    propertyKey: string | symbol ) => void;
    

    案例

    function logProperty(target: any, key: string) {
      delete target[key];
    
      const backingField = "_" + key;
    
      Object.defineProperty(target, backingField, {
        writable: true,
        enumerable: true,
        configurable: true
      });
    
      // property getter
      const getter = function (this: any) {
        const currVal = this[backingField];
        console.log(`Get: ${key} => ${currVal}`);
        return currVal;
      };
    
      // property setter
      const setter = function (this: any, newVal: any) {
        console.log(`Set: ${key} => ${newVal}`);
        this[backingField] = newVal;
      };
    
      // Create new property with getter and setter
      Object.defineProperty(target, key, {
        get: getter,
        set: setter,
        enumerable: true,
        configurable: true
      });
    }
    
    class Person { 
      @logProperty
      public name: string;
    
      constructor(name : string) { 
        this.name = name;
      }
    }
    
    const p1 = new Person("semlinker");
    p1.name = "kakuqo";
    

    方法装饰器

    function LogOutput(tarage: Function, key: string, descriptor: any) {
      let originalMethod = descriptor.value;
      let newMethod = function(...args: any[]): any {
        let result: any = originalMethod.apply(this, args);
        if(!this.loggedOutput) {
          this.loggedOutput = new Array<any>();
        }
        this.loggedOutput.push({
          method: key,
          parameters: args,
          output: result,
          timestamp: new Date()
        });
        return result;
      };
      descriptor.value = newMethod;
    }
    
    class Calculator {
      @LogOutput
      double (num: number): number {
        return num * 2;
      }
    }
    
    let calc = new Calculator();
    calc.double(11);
    // console ouput: [{method: "double", output: 22, ...}]
    console.log(calc.loggedOutput);
    

    参 数装饰器

    function Log(target: Function, key: string, parameterIndex: number) {
      let functionLogged = key || target.prototype.constructor.name;
      console.log(`The parameter in position ${parameterIndex} at ${functionLogged} has
        been decorated`);
    }
    
    class Greeter {
      greeting: string;
      constructor(@Log phrase: string) {
        this.greeting = phrase; 
      }
    }
    
    
  • 相关阅读:
    IO输入输出流
    IDEA项目创建的保存方式
    JAVA File类的学习
    构造方法私有化
    写好文献综述的5个技巧
    毕业设计:文献参考(20)
    毕业设计:文献参考(19)
    毕业设计:文献参考(18)
    毕业设计:文献参考(17)
    毕业设计:文献参考(16)
  • 原文地址:https://www.cnblogs.com/boyGdm/p/14488928.html
Copyright © 2011-2022 走看看