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提供了一个新的方式。 ```ts

// This is a generic method to create an object function createObject(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("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' }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端杂货铺

前端开发中的字符编码

前端开发过程中会接触各种各样的编码,比较常见的主要是UTF-8和HTML实体编码,但是web前端的世界却不止这两种编码,而且编码的选择也会造成一定的问题,如前后...

35880
来自专栏信安之路

php 不用字母,数字和下划线写 shell

还有这个师傅的 《记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门)》

47010
来自专栏Java与Android技术栈

Scala学习笔记(七)

在这里what()方法报错了,主要是因为还缺少了对Cylinder的匹配,只要改成如下的代码就可以正常运行了。

9430
来自专栏AhDung

【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed

之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码:

30730
来自专栏nimomeng的自我进阶

《Objective-C基础教程》笔记

1.xcode中,oc的.m文件代表message,指的是Objective-C的一个主要特性。 2.NS前缀的来历要追溯到次公局包还被成为NextStep,...

8920
来自专栏Jackson0714

PHP内核之旅-3.变量

15840
来自专栏听雨堂

获得定长字符串

        C#中的字符串是Unicode编码,length是Unicode的Char的个数。所以,假如一个字符串中中英文混杂,又想获得一个固定宽度的字符串...

25160
来自专栏calvin

【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--参数自动映射篇(6/8)

路由、action的扫描、发现、注册搞定之后,后来我发现在我们的action里面获取参数往往都是通过request对象来一个一个获取。同样的一行代码我们不厌其烦...

12420
来自专栏盛国存的专栏

A Bite of GoLang(上)

A bite of GoLang(浅尝GoLang),本文只是Go语言的冰山一角,本文包含作者学习Go语言期间积累的一些小的经验,同时为了方便让读者了解到Go语...

561100
来自专栏上善若水

002-golang- 命令行参数处理及flag包

16630

扫码关注云+社区

领取腾讯云代金券