ECMAScript+ 面试宝典

TypeScript

装饰器、静态类型、类型注解、类型推断、泛型、类型定义文件、模块化、打包编译、装饰器、Metadata、设计模式、元祖

TS 特有的东西:typeof,keyof, infer

https://github.com/typescript-exercises/typescript-exercises

为什么需要 TypeScript§

  • TypeScript 的基础特性:

  • 使用编译为 JavaScript 的更高级的语言优点:

    • 修复了 JavaScript 中一些长期问题,并摒弃了 JavaScript 不好的做法。
    • 在 JavaScript 的基础上提供一些语法糖,使我们能够编写更短的代码。ES2015 对语法糖支持的更好。
    • 对于需要长时间维护的大型项目,静态类型非常好用。
  • 使用编译为 JavaScript 的更高级的语言缺点:

    • 由于浏览器只运行 JavaScript、所以需要构建、编译过程,在将代码提供给浏览器之前,需要将代码转移为 JavaScript。
    • 如果 source map 不能很好地映射到预编译的源代码,调试会很痛苦。
    • 大多数开发人员不熟悉这些语言,需要增加团队成本来学习。

如何理解 DefinitelyTyped 项目?§

TypeScript v1~v4 新特性§

  • v3.x

  • v4.x

    • 可变元组类型
    • Class 从构造函数推断成员变量类型:在构造函数里对成员变量的赋值可以直接为成员变量推导类型。
    • catch error 定义为 unknown 类型:以保证后面的代码以健壮的类型判断方式书写
    • 支持 jsxFragmentFactory 参数定义 Fragment 工厂函数
    • 构建速度提升,提升了 --incremental + --noEmitOnError 场景的构建速度
    • 支持 --incremental + --noEmit 参数同时生效。
    • 支持 @deprecated 注释, 使用此注释时,代码中会使用 删除线 警告调用者。
    • 局部 TS Server 快速启动功能,打开大型项目时,TS Server 要准备很久,Typescript 4 在 VSCode 编译器下做了优化,可以提前对当前打开的单文件进行部分语法响应。
    • 更智能的自动导入, 现在 package.json dependencies 字段定义的依赖将优先作为自动导入的依据,而不再是遍历 node_modules 导入一些非预期的包。

TypeScript 和 Babel 有什么区别?§

  • TypeScript 是一门语言、Babel 是一个工具。
  • ......

TypeScript 的内置类型都有哪些?§

  • ECMAScript 的内置对象:BooleanErrorDateRegExp 等。
  • DOM 和 BOM 的内置对象:DocumentHTMLElementEventNodeList 等。
  • TypeScript 核心库的定义文件:TypeScript 核心库的定义文件中定义了所有浏览器环境需要用到的类型,并且是预置在 TypeScript 中的。
  • 第三方类型:如 @types/node

TypeScript支持哪些面向对象的术语?§

  • 模块、类、接口、封装、继承、多态、数据类型、成员函数

如何理解 TypeScript 泛型?§

  • 泛型支持递归
type ListNode<T> = {
  data: T;
  next: ListNode<T> | null;
};

如何编写 tsconfig.json?§

  • 常用的编译配置:
    • allowJs:允许编译 js 文件
    • sourceMap:生成一个 .map.js 的文件,用于其他工具来 debugg,类似于 webpack 的 sourceMap
    • noImplicitAny:不允许用 any,如果初学 ts,建议项目部太复杂的情况下,可以借此来进行限制,前置自己培养对 ts 的理解
    • module && target:target 是编译成哪个版本的 js(es3、es5、es6...);module 是模板生成的形式。默认情况下,当 target 是 es3 的时候,那 module 默认为 commonjs 形式,否则为 es6 形式。
      • 注意(和 outFile 搭配使用):生成的模块形式:none、commonjs、amd、system、umd、es6、es2015 或 esnext 只有 amd 和 system 能和 outFile 一起使用 target 为 es5 或更低时可用 es6 和 es2015
    • lib:引入 ES 的功能库,比如想在项目中用js中Set,Map等新的数据结构,或 promise 等,那要在 lib 中引入 es2015。
    • removeComments 编译出的文件是否带注释,当为 false 的时候可以减少编译出文件的体积。
    • allowSyntheticDefaultImports:为 false 的时候,引入模块的时候必须以 * as 的形式
    • jsx:如果用 tsx 文件(React-ts)那么该项要配置成 jsx:"react"
    • baseUrl
    • paths:必须和 baseUrl 联用

unknown 和 any 类型的区别?§

unknown 类型不能赋值给除了 unknown 或 any 的其他任何类型,使用前必需显式进行指定类型,或是在有条件判断情况下能够隐式地进行类型推断的情况。

  • unknown 类型,它是 any 类型对应的安全类型。
  • unknown 和 any 的主要区别是,unknown 类型会更加严格:在对 unknown 类型的值执行大多数操作之前,我们必须进行某种形式的检查。而在对 any 类型的值执行操作之前,我们不必进行任何检查

type 和 interface 有什么区别?§

  • interface是接口,type是类型,本身就是两个概念。只是碰巧表现上比较相似。
  • 希望定义一个变量类型,就用type,如果希望是能够继承并约束的,就用interface。
  • 如果你不知道该用哪个,说明你只是想定义一个类型而非接口,所以应该用type。
  • 相同点:都可以描述一个对象或者函数
  • 不同点
    • interface 可以 extends, 但 type 是不允许 extends 和 implement 的,但是 type 缺可以通过交叉类型 实现 interface 的 extend 行为
    • interface 能够合并多个相同命名的声明
    • interface 可以 extends type, type 也可以 与 interface 类型 交叉
    • type 可以声明基本类型别名,联合类型,元组等类型
    • type 语句中还可以使用 typeof 获取实例的 类型进行赋值
// Type 一些骚操作
type StringOrNumber = string | number;  
type Text = string | { text: string };  
type NameLookup = Dictionary<string, Person>;  
type Callback<T> = (data: T) => void;  
type Pair<T> = [T, T];  
type Coordinates = Pair<number>;  
type Tree<T> = T | { left: Tree<T>, right: Tree<T> };

动手实现 [P in ArrType]?: string[]§

export type TestType = {
  [P in ArrType]?: string[]
}

动手实现装饰器§

/**
 * 处理异常装饰器, 挂在需要实现try/catch的方法上
 * @param fn
 * @constructor
 */
export const Throwable = (fn?: () => () => void) => {
  return function (target: any, key: any, descriptor: any) {
    const original = descriptor.value
    descriptor.value = function (...args: any[]) {
      const f = fn ? fn() : undefined
      try {
        original.apply(this, args)
      } catch (e) {
        notificationErrorLog(e)
      } finally {
        f && f()
      }
    }
  }
}

Typescript 中的模块有什么特点?§

TypeScript 中的枚举?§

如何检查 TypeScript 中的 null 和 undefined?§

TypeScript 是如何支持函数重载的?§

TypeScript 中 HTML 本身的类型?§

  • HTMLElement

动手实战常见的 Type Assertion?§

/* Checks if T1 equals to T2. */
export type IsTypeEqual<T1, T2> = IsNotAny<T1> extends false ? false : (
    IsNotAny<T2> extends false ? false : (
        [T1] extends [T2] ? ([T2] extends [T1] ? true : false): false
    )
);

/* Checks if T2 can be assigned to T1. */
export type IsTypeAssignable<T1, T2> = IsNotAny<T1> extends false ? false : (
    IsNotAny<T2> extends false ? false : (
        [T2] extends [T1] ? true : false
    )
);

/**
 * Returns `false` if `any` is specified, otherwise returns `true`.
 * @see https://stackoverflow.com/a/49928360/3406963
 */
export type IsNotAny<T> = 0 extends (1 & T) ? false : true;

/* Returns true for false and vice versa. */
export type Not<T> = [T] extends [true] ? false : true;

/**
 * Extracts and returns the first argument of the specified function.
 */
export type FirstArgument<T> = T extends (arg1: infer A, ...args: any[]) => any ? A : never;

/**
 * Extracts and returns the second argument of the specified function.
 */
export type SecondArgument<T> = T extends (arg1: any, arg2: infer A, ...args: any[]) => any ? A : never;

/* Extracts and returns the third argument of the specified function. */
export type ThirdArgument<T> = T extends (arg1: any, arg2: any, arg3: infer A, ...args: any[]) => any ? A : never;

/* Extracts and returns array element type. */
export type ArrayElement<T> = T extends (infer I)[] ? I : never;

/* A simple type assertion function which always expects a true-type. */
export function typeAssert<T extends true>() {}