20210827


TypeScript 相关问题

1.枚举和常量枚举(const枚举)的区别

  • 枚举会被编译时会编译成一个对象,可以被当作对象使用

  • const枚举会在ts编译期间被删除,避免额外的性能开销

    // 代码示例
    
    // 编译之前
    enum test {
      a=1,
      b=1
    }
    const enum testconst {
      aa=1,
      bb=1
    }
    
    // 编译之后
    var test;
    (function (test) {
        test[test["a"] = 1] = "a";
        test[test["b"] = 1] = "b";
    })(test || (test = {}));
    
    //可以看到编译之后只有enum枚举并没有const枚举

2.ts中如何获取枚举联合类型的key?

type Name = { name: string }
type Age = { age: number }
type Union = Name | Age

// infer可以理解为条件句型中的类型推导
type UnionKey<P> = P extends infer P ? keyof P : never

type T = UnionKey<Union>

3.const和readonly的区别

  • const用于变量,readonly用于属性

  • const在运行时检查,readonly在编译时检查

  • 使用const变量保存的数组,可以使用push,pop等方法。但是如果使用ReadonlyArray<number>声明的数组不能使用push,pop等方法。

    4.ts中 ?.、??、!.等符号的含义?

  • ?. 可选链

  • ?? ?? 类似与短路或,??避免了一些意外情况0,NaN以及””,false被视为false值。只有undefind,null被视为false值。

  • !. 在变量名后添加!,可以断言排除undefined和null类型

  • _ , 声明该函数将被传递一个参数,但您并不关心它

    // ??
    let x = foo ?? bar();
    // 等价于
    let x = foo !== null && foo !== undefined ? foo : bar();
    
    // !.
    let a: string | null | undefined
    a.length // error
    a!.length // ok
    复制代码

    5.枚举和 object 的区别

  • 枚举可以通过枚举的名称,获取枚举的值。也可以通过枚举的值获取枚举的名称。

  • object只能通过key获取value

  • 数字枚举在不指定初始值的情况下,枚举值会从0开始递增。

  • 虽然在运行时,枚举是一个真实存在的对象。但是使用keyof时的行为却和普通对象不一致。必须使用keyof typeof才可以获取枚举所有属性名。

    6.never、void 的区别

  • never,never表示永远不存在的类型。比如一个函数总是抛出错误,而没有返回值。或者一个函数内部有死循环,永远不会有返回值。函数的返回值就是never类型。

  • void, 没有显示的返回值的函数返回值为void类型。如果一个变量为void类型,只能赋予undefined或者null。

    7.unkonwn和any

    unknown 类型是 TS3 新增的类型,这个类型与 any 类型类似,可以设置任何的类型值,随后可以更改类型。因此,我们可以将变量先设置为字符串类型,然后再将其设置为数字类型,如果事先不检查类型,使用any类型,调用了不存在的方法,编译时不会报错,代码运行时才会发现错误。但是使用unknown 类型不一样,如果不进行类型判断,执行相关操作编译器就会报错。

  • any

image-20210827083734306.png

可以看到执行tsc any.ts时并不会报错,但是执行node any.ts会报错

  • unknown

image-20210827084016159.png

它认为unknown类型,这个类型没有push方法,当然会报错,除非先判断类型,如果是相关类型且正确执行相关方法,编译器则会顺利通过,虽然有些麻烦,但是相比 any 类型说,更加安全,在代码编译期间,就能帮我们发现由于类型造成的问题,因此在大多的场景,建议使用 unknown 类型替代 any。

let val:unknown = 18;
val = "wxy";
val = new Array();
if (val instanceof Array) {
  val.push(33);
}
console.log(val);

8.interfaces 与 type 之间有什么区别

  • 与接口类型不一样,类型别名可以用于一些其他类型,比如原始类型、联合类型和元组:

    // primitive
    type name = string;
    
    // object
    type posX = { x: number; };
    type posY = { y: number; };
    
    // union
    type pos = posX | posY;
    
    // tuple
    type Data = [number, string];
    • 接口和类型别名都能够被扩展,但语法有所不同。此外,接口和类型别名不是互斥的。接口可以扩展类型别名,而反过来是不行的。
    • 类型别名无法被实现(implements),而接口可以被派生类实现
    • 类型别名重名时编译器会抛出错误,接口重名时会产生合并

    9.Object、object 和 {}

    • object类型:它用于表示非原始类型。
    • JavaScript 中以下类型被视为原始类型:stringbooleannumberbigintsymbolnullundefined
const proto = {};

Object.create(proto);     // OK
Object.create(null);      // OK
Object.create(undefined); // Error
Object.create(1337);      // Error
Object.create(true);      // Error
Object.create("oops");    // Error
  • Object类型:它是所有 Object 类的实例的类型。它由以下两个接口来定义、Object 包括原始

    interface Object {
      constructor: Function;
      toString(): string;
      toLocaleString(): string;
      valueOf(): Object;
      hasOwnProperty(v: PropertyKey): boolean;
      isPrototypeOf(v: Object): boolean;
      propertyIsEnumerable(v: PropertyKey): boolean;
    }
    
    
    interface ObjectConstructor {
      new(value?: any): Object;
      (value?: any): any;
      readonly prototype: Object;
      getPrototypeOf(o: any): any;
    	// ...
    }
    
    declare var Object: ObjectConstructor;
  • {} 类型:它描述了一个没有成员的对象。当你试图访问这样一个对象的任意属性时,TypeScript 会产生一个编译时错误。


Author: wxy
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source wxy !
  TOC