小笔记(typescript篇)

107 阅读4分钟

笔记打算记录,自己整理好的面试题,
争取保持准确性和专业性,然后用直白的语言描述出来,
希望能做成一个API文档,让我日后翻到能直接对着复习就好,
如果也能帮助到你就最好了(我会不定时的更新的)

typescript 常见的数据类型

typescript特点:静态语言、强类型

boolean、number、string、symbol、any、unknown、void(函数无返回值)、null、undefined

  • any:不作任何检查
  • unknown:对比 any 会较为严格,赋值后会限定边界

typescript 泛型的理解

常指先不预设具体的入参类型,由系统根据入参自动设定。常见于:

  1. 函数
  2. 接口
//for in 对象可用此模板
function getValue<T, U>(T extends Object, U extends keyof T): void { }

//常见泛型函数
function array<T>(list: T): T[] { }

typescript 装饰器的理解

装饰器的本质是一个函数,格式为:@xxx

  • 类装饰器:

常规有2种的使用方式,直接调用return一个新的函数(工厂模式)。类装饰器函数的参数target,指向的调用装饰器的class类

  1. 直接调用:全局方法、提前给目标类添加数据、日志记录等
  2. 工厂模式:以继承的形式给类添加变量、返回一个执行特定的逻辑的新类
  3. 多个类装饰器同时执行时,后声明的先执行(从下往上执行)
//直接调用的模式
function AutoRegister(target: any) { 
  // 假设有一个全局注册方法 
  globalRegister(target); 
}

@AutoRegister 
class MyComponent { 
  // 组件逻辑 
}

//工厂模式(返回一个新的函数、类)
function Config(config: { baseUrl: string }) { 
  //支持简单的注册基础变量
  return function (target: Function) { 
    target.prototype.baseUrl = config.baseUrl; 
  }; 
}

function Component(options?: any): any {
  return (target: VueClass<Vue>) => {
    //支持具体的vue全局逻辑
  } 
}

//执行顺序 (下面示例的执行返回顺序是,先执行B装饰器、再A)
@A
@B
class MyClass {
  // 组件逻辑
}
  • 方法装饰器:

常用于class类内部的方法使用,进行一些特定的操作。函数的参数通常是三个方法的名称方法的属性描述

  1. 业务场景常见有:修改方法返回值、加入log记录(衍生出性能监控)、权限控制。
  2. 执行顺序:多个装置器同时执行的时候,和类装饰器一样,从下往上执行
//修改返回值
function ModifyReturnValue(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originalMethod = descriptor.value; // 保存原始方法

  descriptor.value = function (...args: any[]) {
    const result = originalMethod.apply(this, args); // 调用原始方法
    return result + " - modified"; // 修改返回值
  };
}

class Example {
  @ModifyReturnValue
  greet(name: string) {
    return `Hello, ${name}`;
  }
}

从示例中能看到,方法装饰器是需要手动的 apply ,所以在手动执行方法时,就有很多操作空间。例如在执行前后加入log日志,也能根据log进行性能的监控。

  • 属性装饰器:

业务场景可用于:增加属性初始值、为类新增额外的属性、修改属性的描述信息。装饰器的函数有2个参数:目标类属性名称。执行顺序也和前面一致:后声明的装饰器先执行

//属性设定初始值
function DefaultValue(defaultValue: any) {
  return function (target: any, propertyKey: string) {
      target[propertyKey] = defaultValue; // 设置默认值
  };
}

class Settings {
  @DefaultValue(true)
  darkMode: boolean;

  @DefaultValue(10)
  fontSize: number;
}

//修改属性的描述信息 (例如:readonly)
function ReadOnly(target: any, propertyKey: string) {
  const descriptor = {
      writable: false,
      enumerable: true,
      configurable: false,
  };
  Object.defineProperty(target, propertyKey, descriptor);
}
  • gettersetter装饰器:

这个装饰器,可以理解为特殊的 属性装饰器,在装饰器内部定义了gettersetter函数,结合Object.defineProperty,重新定义该属性。

function getter() {}
function setter(val) {}
//重新定义属性的描述信息
Object.defineProperty(target, propertyKey, {
  get: getter,
  set: setter,
  enumerable: true,
  configurable: true,
});

typescript interface和type的理解

type:类型别名
interface:定义对象、函数的接口类型

  • 相同点:

①interface和type都可以用于定义对象和函数
②interface和type都可以被继承

//interface继承 (关键字 extends)
interface A {
  name: string;
}

interface B extends A {
  age: number;
}

//type继承 (关键字 &)
type C = {
  color: string;
}

type D = C & {
  firstName: string;
}

//支持混合继承
interface E extends C {
  // ...
}
type F = A & {
  // ...
}
  • 不同点:

①interface 同名重复声明时,会自动进行合并。type 不支持重复声明
②type(类型别名)可以定义更丰富类型的变量(联合类型、元祖类型、基础类型变量)
③type 可以使用 in 关键字来定义对象类型变量的索引值,interface不行
④type 可以结合 typeof关键字 来定义,interface不行

typescript 推断函数返回类型的方法

当有第三方不确定的函数(未维护具体ts信息),想判断该函数返回的类型

typescript有内置的type,关键字为 ReturnType

//内置的工具 泛型 T 必须为函数类型
ReturnType<T>

type Func = () => string;
// 参数返回 string
type ReturnFunc = ReturnType<Func>;