@panhonhang
2020-02-17T16:24:04.000000Z
字数 3570
阅读 518
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
}