• TypeScript中的怪语法


    TypeScript中的怪语法

    如何处理undefined 和 null

    undefined的含义是:一个变量没有初始化。
    null的含义是:一个变量的值是空。

    undefined 和 null 的最佳实践

    • 核心思想: 避免null pointer错误。
      null is bad

    要避免这个问题,我们需要做到:

    {
        "compilerOptions": {
            "strict": true,
            //...
        }
    }
    
    • 对于不可能是null的变量:
      • 声明不能为 null 和 undefined。
      • 提示编译错误:当使用一个没有初始化的变量,而这个变量不能为undefined的时候。
      • 提示编译错误:当给一个不能为 null 和 undefined 的变量,赋值 null 和 undefined 的时候。
        如果使用了"strictNullChecks" 编译选项,TypeScript编译器默认任何变量都不能为 undefined 和 null。除非显式声明。
    var name: string;   // cannot be null and undefined.
    
    name = undefined;    // Error: [ts] Type 'undefined' is not assignable to type 'string'.
    name = null;         // Error: [ts] Type 'null' is not assignable to type 'string'.
    console.log(name);   // Error: [ts] Variable 'address' is used before being assigned.
    
    • 对于可能是undefined的变量:
      • 使用显式声明
      • 提示编译错误:当使用一个可能为null的变量的时候。
      • 使用前,需要确定不是undefined.
    var address: string | undefined; // can be undefined
    
    class Person {
        name: string;               // cannot be null and undefined
        address?: string;           // can be undefined
    }
    
    var person : Person = {name: "Joe"};
    
    console.log(person.address.toString()); // Error: [ts] Object is possibly 'undefined'.
    
    if (person.address != undefined) {
        console.log(person.address.toString()); //Ok. as we checked the type
    }
    

    Index Type Query - keyof

    keyof 定义了一个Type, 这个Type的值来自于指定的类。

    class Person {
        id: number;
        name: string;
        birthday: Date;
    }
    
    type personPropKeys = keyof Person; // same as: type personPropKeys = "id" | "name" | "birthday"
    
    var propKey : personPropKeys;
    propKey = "id";     // OK
    propKey = "name";   // OK
    propKey = "age";    // Error: [ts] Type '"age"' is not assignable to type '"id" | "name" | "birthday"'.
    
    • 用途 - 生成类的映射类型 - Mapped Types
      keyof的用途是很有趣的。比如:我们希望一个ReadOnlyPerson类,这个类和类Person的属性相同,不过其中每个属性都是只读的。
      TypeScript使用了keyof提供了下面的类:
    // Keep types the same, but make each property to be read-only.
    type Readonly<T> = {
        readonly [P in keyof T]: T[P];
    };
    
    // Same property names, but make the value a promise instead of a concrete one
    type Deferred<T> = {
        [P in keyof T]: Promise<T[P]>;
    };
    
    // Wrap proxies around properties of T
    type Proxify<T> = {
        [P in keyof T]: { get(): T[P]; set(v: T[P]): void }
    };
    

    类的参数属性 - parameter properties

    class Person {
        // same as to define instance fields: id, name, age
        constructor(private id: number, public name: string, readonly age: number) {
        }
    
        get Id() : number {
            return this.id;
        }
    }
    
    var person = new Person(1, "Mary", 14);
    console.log(person.name);
    

    Type: {new(): T}

    {new(): T} 的主要功能是让通用方法可以创建通用类型的对象。

    但是,这个故事有点长。

    • 实现方法1:通过一个方法。
    
    // This is a generic method to create an object
    function createObject<T>(name:string, creator: (arg: string) => T) : T {
        return creator(name);
    }
    
    // now we have a class Person, we want to create it via function createObject
    class Person {
        public constructor(name: string) {
            this.name = name;
        }
    
        name: string;
    }
    
    // we have to define a creator function
    function createPerson(name: string): Person {
        return new Person(name);
    }
    
    // at end, we can create a person
    var person = createObject<Person>("Kate", createPerson);
    
    
    • 实现方法2:使用构造方法。但是行不通。
      但是,对象的创建者的主角是构造对象constructor。
      专门定义一个creator方法也很别扭。
      我们希望写成的代码是这样的,但是有一个编译错误。

    没有研究过为什么这样写行不通。可能是在转义js上有一些问题。

    
    // This is a generic method to create an object
    function createObject<T>(name:string) : T {
        return new T(name);     // Error: [ts] 'T' only refers to a type, but is being used as a value here.
    }
    
    // now we have a class Person, we want to create it via function createObject
    class Person {
        public constructor(name: string) {
            this.name = name;
        }
    
        name: string;
    }
    
    // at end, we can create a person
    var person = createObject<Person>("Kate");
    
    
    • 实现方法3:使用构造方法类型。
      结合以上的方法,TypeScript提供了一个新的方式。
    
    // This is a generic method to create an object
    function createObject<T>(name:string, creator: {new(name: string): T}) : T {
        return new creator(name);
    }
    
    // now we have a class Person, we want to create it via function createObject
    class Person {
        public constructor(name: string) {
            this.name = name;
        }
    
        name: string;
    }
    
    // at end, we can create a person
    var person = createObject<Person>("Kate", Person);
    
    console.log(person);
    
    

    更多的解释

    {new(): T}的类型是一个 Type,因此可以用于定义变量和参数。

    new()是描述构造函数的签名。所以在new()中,也定义参数。比如:{new(name: string): T}
    {new(): T}定义了一个返回类型为 T 的构造函数的Type

    type NewObject<T> = {new(name: string): T};     // type NewPersonType = new (name: string) => Person
    var newPersonType: NewObject<Person> = Person;
    var person2 = new newPersonType("Joe");
    
    // we also can write like this, as {} is the root class of object type.
    type ObjectEmpty = {new(): {}};     // type ObjectEmpty = new () => {}
    

    剩余语法

    剩余参数 - Rest parameters

    function restFunction(first: string, second: string, ...args: string[]): void {
        console.log(args);      // [ 'three', 'four' ]
    }
    
    restFunction("one", "two", "three", "four");
    

    对象传播 - Object Spread and Rest

    // shadow copy
    var objCopy: any = {...obj};
    console.log(objCopy);       // { x: 1, y: 'name', z: 2 }
    console.log(objCopy === obj);   // false
    
    // copy and change
    var obj2 = {a: "age"};
    objCopy = {...obj, z: "zoo"};
    console.log(objCopy);       // { x: 1, y: 'name', z: 'zoo' }
    
    // merge
    var obj2 = {a: "age"};
    objCopy = {...obj, ...obj2};
    console.log(objCopy);       // { x: 1, y: 'name', z: 2, a: 'age' }
    
    // copy and remove
    let {z, ...objCopy2} = obj
    console.log(objCopy2);      // { x: 1, y: 'name' }
    
  • 相关阅读:
    HDU-5534-Partial Tree
    Dire Wolf HDU
    HDU 5119 Happy Matt Friends (14北京区域赛 类背包dp)
    4 Values whose Sum is 0 POJ
    Fliptile POJ
    Face The Right Way POJ
    【Selenium学习】解决chromedriver.exe' executable needs to be in PATH
    【Jenkins学习】修改jenkins显示为中文语言
    【Jenkins学习】Jenkins 批量删除历史构建
    【Tomcat学习】tomcat 日志详解
  • 原文地址:https://www.cnblogs.com/steven-yang/p/7679494.html
Copyright © 2020-2023  润新知