每日一篇——23秋招TS面经(1)

37 阅读4分钟

每日一篇——23秋招TS面经(1)

⭐简要说明 TypeScript 中的类型注解和类型推断的区别,并举例说明。

类型注解是在代码中明确指定变量的类型,使用冒号(:)后跟类型名称的方式进行注解。通过类型注解,开发者可以为变量、函数参数、函数返回值等明确指定类型。

例如:

let num: number = 10;
function add(a: number, b: number): number {
  return a + b;
}

类型推断是 TypeScript 的一项特性,在变量声明时根据变量的初始值自动推导出变量的类型。通过类型推断,开发者可以省略变量的类型注解,让 TypeScript 根据上下文自动推断出变量的类型。

例如:

let num = 10; // 推断为 number 类型
function add(a: number, b: number) { // 推断返回值类型为 number
  return a + b;
}

类型注解和类型推断的区别主要在于显式性和隐式性。类型注解更加明确,可以提高代码的可读性和可维护性,但需要开发者手动指定类型;类型推断更加隐式,可以减少代码的冗余,提高开发效率,但有时可能推断出的类型不符合预期。

⭐请解释 TypeScript 中的泛型,并举例说明其用途和使用方式。

泛型在 TypeScript 中的使用方式非常灵活,可以用于函数、类、接口等各种场景。通过使用泛型,我们可以在定义时不指定具体的类型,而是使用一个占位符(通常为单个大写字母,比如 T)来代表类型,使得代码具有更高的灵活性和重用性。

泛型的主要用途包括:

  1. 提供类型安全的容器:通过使用泛型,可以创建安全的数据容器,例如数组或集合类型,使其只能存储指定类型的元素。
function toArray<T>(arg: T): T[] {
  return [arg];
}

const arr = toArray<number>(10); // 创建存储数字类型的数组
  1. 增强代码的可扩展性:通过将类型参数化,可以编写更通用的代码,减少代码的重复和冗余,并且能够应对多种类型的需求。
function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

const mergedObj = merge({ name: 'Tom' }, { age: 20 }); // 合并两个对象的属性
  1. 可以在类或接口中使用泛型,实现更灵活的类型约束和抽象。
interface Container<T> {
  value: T;
  getValue(): T;
}

class NumberContainer implements Container<number> {
  value: number;

  constructor(value: number) {
    this.value = value;
  }

  getValue(): number {
    return this.value;
  }
}

总结:泛型是 TypeScript 中非常强大和重要的特性,它能够增强代码的类型安全性和可扩展性。通过合理应用泛型,我们可以编写更灵活、通用、可维护的代码。

⭐请解释 TypeScript 中的装饰器是什么,以及如何应用装饰器。

装饰器是一种特殊类型的函数,可以用于修改类、属性或者方法的行为。装饰器通过在被修饰的目标周围包裹额外的逻辑来实现对目标进行扩展或者改变。

装饰器可以定义在类、属性和方法上,它们分别称为类装饰器、属性装饰器和方法装饰器。装饰器函数可以接收不同参数,参数的数量和类型取决于装饰器所应用的目标类型。

下面我们来逐个说明装饰器的定义,并举例装饰器分别定义在类、属性和方法上的情况:

  1. 类装饰器(Class Decorator):

    • 定义:类装饰器是应用于类构造函数的函数。它接收一个参数,即被装饰的类的构造函数。

    • 示例:

      function logClass(target: any) {
          console.log(`Class ${target.name} is decorated`);
      }
      
      @logClass
      class MyClass {
          // 类的定义
      }
      

      在这个例子中,logClass 是一个类装饰器,它被应用到 MyClass 类上。当我们使用 @logClass 语法将装饰器应用到类上时,装饰器函数会在类的构造函数上进行操作,这里会输出 "Class MyClass is decorated"。

  2. 属性装饰器(Property Decorator):

    • 定义:属性装饰器是应用于类的属性的函数。它接收两个参数,分别是目标类的原型、属性名。

    • 示例:

      function logProperty(target: any, propertyKey: string) {
          console.log(`Property ${propertyKey} is decorated in class ${target.constructor.name}`);
      }
      
      class MyClass {
          @logProperty
          myProperty: string;
      }
      

      在这个例子中,logProperty 是一个属性装饰器,它被应用到 MyClass 类的 myProperty 属性上。装饰器函数会在属性的定义阶段进行操作,这里会输出 "Property myProperty is decorated in class MyClass"。

  3. 方法装饰器(Method Decorator):

    • 定义:方法装饰器是应用于类的方法的函数。它接收三个参数,分别是目标类的原型、方法名和方法的属性描述符。

    • 示例:

      function logMethod(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
          console.log(`Method ${propertyKey} is decorated in class ${target.constructor.name}`);
      }
      
      class MyClass {
          @logMethod
          greet(name: string) {
              console.log(`Hello, ${name}!`);
          }
      }
      

      在这个例子中,logMethod 是一个方法装饰器,它被应用到 MyClass 类的 greet 方法上。装饰器函数在方法的定义阶段进行操作,这里会输出 "Method greet is decorated in class MyClass"。

通过使用装饰器,我们可以方便地扩展或者修改类、属性或者方法的行为,实现一些额外的逻辑或者功能。装饰器提供了一种优雅且灵活的方式来对代码进行元编程。