@panhonhang
        
        2020-02-17T08:24:04.000000Z
        字数 3570
        阅读 683
    javascript
unknown 与 any区别:
let value: unknown;
value.foo.bar;  // ERROR
value();        // ERROR
new value();    // ERROR
value[0][1];    // ERROR
let value: any;
value.foo.bar;  // OK
value();        // OK
new value();    // OK
value[0][1];    // OK
never 类型表示的是那些永不存在的值的类型,never 类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是 never 的子类型或可以赋值给 never 类型(除了never本身之外)。
即使any也不可以赋值给never。
两个场景中 never 比较常见:
// 抛出异常的函数永远不会有返回值 
function error(message: string): never { 
    throw new Error(message); 
}
// 空数组,而且永远是空的 
const empty: never[] = []
数字枚举 
默认的数字类型,而且默认从0开始依次累加。设置第一个值的话会从第一个开始来加。 
enum Direction { 
    Up, 
    Down, 
    Left, 
    Right 
} 
console.log(Direction.Up === 0); // true 
console.log(Direction.Down === 1); // true 
console.log(Direction.Left === 2); // true 
console.log(Direction.Right === 3); // true
字符串枚举
enum Direction { 
    Up = 'Up', 
    Down = 'Down', 
    Left = 'Left', 
    Right = 'Right' 
}
console.log(Direction['Right'], Direction.Up); // Right Up
异构枚举: 
混合字符串和数字 
enum BooleanLikeHeterogeneousEnum { 
No = 0, 
Yes = "YES", 
}
反向枚举 
可以通过枚举值获取枚举名字 
原理:枚举本质是这样的,被编译以后。 
enum Direction { 
    Up, 
    Down, 
    Left, 
    Right 
}
console.log(Direction[0]); // Up
console.log(Direction.Up); // 0
var Direction; 
(function (Direction) { 
    Direction[Direction["Up"] = 10] = "Up"; 
    Direction[Direction["Down"] = 11] = "Down"; 
    Direction[Direction["Left"] = 12] = "Left"; 
    Direction[Direction["Right"] = 13] = "Right"; 
})(Direction || (Direction = {}));
常量枚举:枚举其实可以被 const 声明为常量,好处在于可以提升性能。 
原理:枚举类型本来会被编译为 JavaScript 对象。但是常量枚举就会直接使用对象的值,而把对象删除掉。
declare let a: Direction
enum Animal { 
    Dog, 
    Cat 
}
a = Direction.Up // ok 
a = Animal.Dog // 不能将类型“Animal.Dog”分配给类型“Direction”
a 声明为 Direction 类型,可以看成我们声明了一个联合类型 Direction.Up | Direction.Down | Direction.Left | Direction.Right
为枚举添加静态方法 
原理借助命名空间,例子: 
enum Month { 
    January, 
    February, 
    March, 
    April, 
    May, 
    June, 
    July, 
    August, 
    September, 
    October, 
    November, 
    December, 
} 
我们要编写一个静态方法,这个方法可以帮助我们把夏天的月份找出来:
function isSummer(month: Month) { 
    switch (month) { 
        case Month.June: 
        case Month.July: 
        case Month.August: 
            return true; 
        default: 
            return false 
    } 
} 
想要把两者结合就需要借助命名空间的力量了:
namespace Month { 
    export function isSummer(month: Month) { 
        switch (month) { 
            case Month.June: 
            case Month.July: 
            case Month.August: 
                return true; 
            default: 
                return false 
        } 
    } 
}
console.log(Month.isSummer(Month.January)) // false
继承接口 
我们可以用继承的方式,继承 User 的接口。
interface VIPUser extends User { 
    broadcast: () => void 
}
抽象类 
不能直接实例化抽象类,必须先创建子类继承基类,然后实例化子类
abstract class Animal { 
    abstract makeSound(): void; 
    move(): void { 
        console.log('roaming the earch...'); 
    } 
}
class Cat extends Animal { 
    makeSound() { 
        console.log('miao miao') 
    } 
}
const cat = new Cat()
cat.makeSound() // miao miao 
cat.move() // roaming the earch...
访问限定符 
public:默认为public,被修饰的成员可以被外部访问; 
private:只能是类的内部访问 
protected 可以被子类和类的内部访问
函数重载overload
// 重载 
interface Direction { 
    top: number 
    right: number 
    bottom: number 
    left: number 
}
function assigned(all: number): Direction 
function assigned(topAndBottom: number, leftAndRight: number): Direction 
function assigned(top: number, right: number, bottom: number, left: number): Direction
// 代码实现函数不可被调用 
function assigned (a: number, b?: number, c?: number, d?: any) { 
    if (b === undefined && c === undefined && d === undefined) { 
      b = c = d = a 
    } else if (c === undefined && d === undefined) { 
      c = a 
      d = b 
    } 
    return { 
      top: a, 
      right: b, 
      bottom: c, 
      left: d 
    } 
}
静态编写的时候并不确定传入的参数到底是什么类型,那么我们需要变量,这个变量代表了传入的类型,然后再返回这个变量,它是一种特殊的变量,只用于表示类型而不是值。
例子: 
    function swap(tuple: [T, U]): [U, T] { 
        return [tuple[1], tuple[0]]; 
    }
swap([7, 'seven']); // ['seven', 7]
泛型数组 
Array、[]
泛型接口 
interface ReturnItemFn { 
    (para: T): T 
} 
那么当我们想传入一个number作为参数的时候,就可以这样声明函数:
const returnItem: ReturnItemFn = para => para
泛型类 
class Stack { 
    private arr: T[] = []
public push(item: T) {
    this.arr.push(item)
}
public pop() {
    this.arr.pop()
}
}
泛型约束 
  的方式约束泛型
因为我们给参数 obj 定义的类型就是 object,在默认情况下它只能是 {},但是我们接受的对象是各种各样的,我们需要一个泛型来表示传入的对象类型,比如 T extends object:
function getValue(obj: T, key: string) { 
  return obj[key] // error 
}