yuxino / blog

🎬 Life's a Movie
17 stars 2 forks source link

Typescript 小记 #80

Closed yuxino closed 3 years ago

yuxino commented 6 years ago

Enum

Typescript的Enum给Javscript提供了更加友好的枚举方式。给数字赋上了更加友好的名字。

enum Color {Red, Green, Blue}
let c: Color = Color.Green;

默认的数字是从0开始的,但是你也是可以改的。比如下面的从1开始。

enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;

当然你还可以是自定义的数字。

enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;

如果你想知道枚举的值是什么,而不是单纯的数字。你可以进行类型转换。

enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2];

console.log(colorName); // 这样就会显示Green

但是如果你直接通过Color.Green访问是无法编译过去的

Nerver

Nerver 用在抛出异常和永不返回值的函数里。下面有几个例子。

// Function returning never must have unreachable end point
// 
function error(message: string): never {
    throw new Error(message);
}

// Inferred return type is never
function fail() {
    return error("Something failed");
}

// Function returning never must have unreachable end point
function infiniteLoop(): never {
    while (true) {
    }
}

Type assertions

类型断言/转换。告诉编译器你知道你在干啥,强转类型。有两种写法。一种是尖括号。一种是使用as作为关键字。

尖括号写法如下

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;

这两种语法都是等价的。唯一的区别是在JSX里面只能用as

readyonly

readyonley用在interface里,表示这个属性值是只读的,只有在初次赋值的时候是允许赋值的,之后都是不允许的。

interface Point {
    readonly x: number;
    readonly y: number;
}

let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!

ReadonlyArray

ReadonlyArray是一个不可以修改的数组。为了避免我们修改原数组。删除了所有的变异方法。在会后一行里我们试图把ReadyonlyArray的ro直接赋值给a在这里也是不允许的。

let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!

但是我们可以通过as赋值。

a = ro as number[];

readonly vs const

常量变量使用const。属性读写使用readonly

Excess Property Checks

Excess Property Checks的意思是多余的类型检测。通常我们会定义好一些optional也就是可选的类型。但是如果我们传一些不存在的类型。在Js里面不会出什么问题。会被悄悄的忽略掉,但是在Ts里面会认为是异常,出现警告。

interface SquareConfig {
    color?: string;
    width?: number;
}

function createSquare(config: SquareConfig): { color: string; area: number } {
    // ...
}

let mySquare = createSquare({ colour: "red", width: 100 });

我们看这个colour。Ts给出了警告。

// error: 'colour' not expected in type 'SquareConfig'
let mySquare = createSquare({ colour: "red", width: 100 });

事实上我们可以绕过这个检查。比如这样。

let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);

但是有点沙雕。所以我们换一种方式。

interface SquareConfig {
    color?: string;
    width?: number;
    [propName: string]: any;
}

让[propName]变得动态。让类型变得无关紧要。这样编译器就不会警告了。

let squareOptions = { colour: "red", width: 100 };
let mySquare = createSquare(squareOptions);

Class

private 修饰符

Class的private修饰符编译出来的结果其实并不是真的是private的。只是在用的时候警告。并不是真正意义上的。

readonly

readonly也可以作用在class的属性上面。

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.

Function

contextual typing

一般写函数的类型会这样写

let myAdd: (x: number, y: number) => number =
    function(x: number, y: number): number { return x + y; };

但是其实还可以这样:

// myAdd has the full function type
let myAdd = function(x: number, y: number): number { return  x + y; };

// The parameters 'x' and 'y' have the type number
let myAdd: (baseValue: number, increment: number) => number =
    function(x, y) { return x + y; };

第一种是完全的函数类型。第二种叫做contextual typing。右侧不写任何的类型或者返回类型由Ts自己推到出来。

Module,NameSpace的理解

个人认为只有在写一整个库的声明的时候需要用到Module。Namespace的话是不能import的,并且是全局的,在写一些东西的时候很有用。平时写的js文件只要export就好了,别想那么多。

声明合并

Declaration Type Namespace Type Value
Namespace X   X
Class   X X
Enum   X X
Interface   X  
Type Alias   X  
Function     X
Variable     X

详细看这里