TS面试题总结

475 阅读15分钟

1.什么是TS?

TypeScript 是一种开源的编程语言,它是 JavaScript 的一个超集,添加了静态类型检查和其他一些特性。TypeScript 提供了更强大的静态类型系统,有助于编写更可靠和可维护的 JavaScript 代码。

2.项目中为什么要使用TS

在项目中使用 TypeScript (TS) 有一些好处,下面是其中一些常见的好处:

  1. 强大的静态类型检查:TypeScript 提供了静态类型系统,允许在编码阶段检测出潜在的类型错误和逻辑错误。这可以帮助开发者在开发过程中捕获和修复错误,减少在运行时出现的错误。类型检查还可以提供更好的代码提示和自动完成功能,提高代码的可读性和可维护性。
  2. 更好的代码组织和可维护性:TypeScript 支持模块化和面向对象的编程,可以帮助开发者更好地组织和管理代码。通过使用接口、类、命名空间等特性,可以提高代码的可读性、可维护性和可扩展性。
  3. 更好的开发工具支持:TypeScript 提供了丰富的开发工具支持,包括代码编辑器(如Visual Studio Code)、静态分析工具和调试器等。开发者可以受益于强大的工具集,使开发过程更高效、更准确。
  4. 渐进式采用:TypeScript 兼容 JavaScript,可以将现有的 JavaScript 代码渐进式地迁移到 TypeScript。这意味着可以逐步引入 TypeScript,无需一次性重写整个代码库,从而降低了迁移成本。
  5. 社区和生态系统支持:TypeScript 是一个活跃的开源项目,有庞大的社区和生态系统支持。有大量的第三方库和工具可用于 TypeScript,并且有许多优秀的 TypeScript 资源和学习资料可供参考。

3.说说你知道的ts中的数据类型

ts是js的超集,所以js的数据类型ts都支持

js中的基础数据类型:Number,String,Null,Undefined,Boolean,Symbol...

js中的引用数据类型:Function,Array,Object...

此外ts还有自己特有的数据类型:

enum  枚举                       any  任意                        

generic  泛型                    tuple 元组 

unknown  未知                    void 没有返回值

never 从不出现                   ...

4.你了解any类型吗,谈谈你对他的理解,一般any你会用在什么场景下

了解,当我们在 TypeScript 中声明变量或函数参数的类型时,有时候无法确定其具体的类型,或者希望允许任何类型的赋值。这时可以使用 “any” 类型来表示这种不确定或任意类型。

场景:

  1. 类型转换不确定的情况:在某些情况下,我们无法确定一个值的具体类型,或者希望将一个变量用于多种类型。这时可以使用 “any” 类型来暂时接受任意类型,并进行相应的类型转换或处理。
  2. 动态数据的处理:当处理来自外部或动态数据源的数据时,我们通常无法提前知道数据的具体类型。在这种情况下,可以使用 “any” 类型来容纳任意类型的数据,并在运行时进行相应的类型检查和处理。

5.unknown和any有什么区别

在 TypeScript 中,“unknown” 和 “any” 是两种表示不确定类型的机制,但它们有一些关键区别。

  1. 类型安全性:

    • “unknown”: 当一个值的类型被声明为 “unknown” 时,它是一个类型安全的容器。这意味着你不能直接对 “unknown” 类型的值进行操作,除非你显式地进行类型检查或类型断言,将其转换为其他已知的类型。这可以提供更强的类型安全性,因为它阻止你在不明确类型的情况下进行随意的操作。
    • “any”: 当一个值的类型被声明为 “any” 时,它是类型不安全的,可以接受任何类型的赋值,并且可以随意进行操作,而不会引发类型检查或编译错误。这样的灵活性可能会在某些情况下带来方便,但也降低了类型安全性。
  2. 类型推断与类型信息

    • “unknown”: TypeScript 对 “unknown” 类型的值具有更严格的推断规则。当你执行对 “unknown” 类型的操作时,通常需要进行类型检查或类型断言,以便 TypeScript 可以推断出具体的类型信息。这有助于处理类型不确定的情况,并鼓励对类型进行明确的处理。
    • “any”: 当一个值的类型被声明为 “any” 时,TypeScript 将对其进行最小化的类型检查,并且对它进行的操作不会对类型系统产生影响。TypeScript 不会提供关于该值的具体类型信息,也不会进行类型推断。
  3. 类型约束

    • “unknown”: 当一个值的类型被声明为 “unknown” 时,它在被赋值给其他变量或作为函数参数传递时,会强制进行类型检查或类型断言。这确保了类型的一致性和明确性。
    • “any”: 当一个值的类型被声明为 “any” 时,它可以被赋值给任何类型的变量,并且可以传递给任何函数参数,而不会强制进行类型检查。这允许了更大的灵活性,但也丧失了一些类型约束和类型安全性。

综上所述,“unknown” 和 “any” 都可以用来表示不确定类型,但它们在类型安全性、类型推断与信息和类型约束等方面存在差异。建议在编写 TypeScript 代码时,尽量避免使用 “any”,而是使用更具体的类型或将类型不确定的值声明为 “unknown” 来提高代码的类型安全性和可维护性。

6.3. never表示什么,unknown表示什么,分别用在什么场景下。

never: 永远不可能出现值 unknown: 有多种可能性,但是具体哪一种不知道

场景: never -> 函数中最终的结果是抛出一个错误,这个时候就可以把函数的返回值标注成never unknown -> 类型断言的时候,需要用unknown做中转

7.interface 和 type的去区别

在 TypeScript 中,interface 和 type 都用于定义自定义类型,但它们有一些关键区别。

主要区别如下:

  1. 语法差异:

    • interface:使用 interface 关键字定义接口,可以在接口中声明属性、方法等。例如:interface Person { name: string; age: number; }
    • type:使用 type 关键字定义类型别名,可以给现有的类型起一个新的名字。例如:type Person = { name: string; age: number; };
  2. 扩展性差异:

    • interface:支持扩展其他接口,使用 extends 关键字实现接口之间的继承。例如:interface Employee extends Person { salary: number; }
    • type:支持联合类型、交叉类型和元组等高级类型的定义,可以使用泛型进行更复杂的类型操作。例如:type Name = string | null; 或 type Point = { x: number; y: number; } & { color: string; }
  3. 同名合并行为:

    • interface:可以多次声明同一个名字的接口,并且它们会自动合并为一个接口。例如:interface Person { name: string; } interface Person { age: number; }
    • type:不能直接多次声明同一个名字的类型别名,因为它们会覆盖原来的定义。
  4. 可读性差异:

    • interface:常用于定义对象的形状,更符合直觉,可读性更好,因为它定义了一种新的类型。
    • type:更灵活,可以给现有类型起别名,以便引用或复用。可以用于定义复杂的类型。

根据需求的不同,选择使用 interface 还是 type 取决于你的具体场景和个人偏好。通常,使用 interface 来描述对象和类的形状,使用 type 来定义更复杂的类型别名、联合类型或交叉类型。在项目中,你也可以同时使用它们,根据具体情况进行选择。

8.什么是字面量类型数据,什么场景下会出现字面量数据

字面量类型是指将具体的字面值作为类型的一部分。它允许我们将值限定为特定的字面量,而不仅仅是某个类型的子集。

在 TypeScript 中,我们可以使用字面量类型来表示一个具体的值。

当我们给一个变量设置值的时候可以使用字面量类型,使这个数据只能存放字面量数据的某一个子集

type Gender = "man" | "woman" 
const genser: Gender = "man"; // 只能是 "man", "woman" 之一

9.TS中如何使用类型断言,一般使用在什么场景下,需要注意什么?

开发者清楚数据的类型,但是ts无法理解,可以强制告诉ts编译器,当前数据是什么类型.

场景: 一个变量存在多种类型的可能性,但是实际在传递值的时候可能只有一种.

注意: ts中无法直接把一种类型断言为另外一种类型,中间需要unknown做中转.

10.TS在类中支持的类中的修饰符有哪些,分别有什么特点。

  • public 公开的,可以在任何位置使用属性
  • protected 受保护的, 使用了该修饰符的属性或者方法只能在类本身和子类中使用
  • private 私有的, 只能在自身的类中使用

11.简单聊聊你对TS中的枚举类型数据的理解

enum 中的常量在不赋值的情况会自动进行分配值,值从0开始,逐步递增

enum Direction { 
    Up, 
    Down, 
    Left, 
    Right 
} 
let myDirection: Direction = Direction.Up;

在上面的示例中,我们定义了一个名为 Direction 的枚举类型,并指定了一组常量值。默认情况下,这些常量值从0开始依次递增,所以Up的值为0,Down的值为1,以此类推。

然后,我们声明了一个变量 myDirection 并将其类型设置为 Direction。我们可以将枚举类型的值分配给变量,例如 Direction.Up

如果这么设置的话:

enum Direction { 
    Up=1 
    Down, 
    Left=10 
    Right 
}

那么

  • Up 的值为 1
  • Down 的值为 2
  • Left 的值为 10
  • Right 的值为 11

12.谈谈你对TS中的泛型的理解

在 TypeScript 中,泛型(Generics)是一种特性,它允许我们在定义函数、类或接口时使用参数化类型

简单来说就是: 动态类型标注,将标注的类型决定权给使用者。

泛型的主要用途是增强代码的可重用性、类型安全性和灵活性。下面是一些泛型的用途和好处:

  1. 类型安全性:使用泛型可以在编译时提供类型检查和类型推断,避免运行时的类型错误。
  2. 代码重用:使用泛型,我们可以编写一次具有通用类型的代码,然后在不同的上下文中重复使用它。这样可以减少重复代码的量,并且提高代码的可维护性。
  3. 灵活性:泛型使代码更加灵活,因为它们可以与不同类型的数据一起使用。我们可以构建适应不同数据类型的通用函数或类。
  4. 抽象数据类型:泛型可以用于创建抽象数据类型,使代码更具扩展性和可定制性。这样的数据类型可以根据实际需求进行类型参数化。
  5. 函数的泛型:通过在函数签名中使用泛型,我们可以在调用函数时指定函数参数和返回值的类型,在编译时进行类型检查,并使函数更加灵活和通用。

13.解释一下什么是类型推断和类型断言

当我们在 TypeScript 中声明变量时,可以通过两种方式来确定变量的类型:自动类型推断和类型断言。

自动类型推断(Type Inference)是 TypeScript 编译器根据代码上下文自动推断出变量的类型,而无需显式指定类型。TypeScript 根据变量的赋值表达式、函数返回值等进行推断。

下面是一个示例:

let foo = 42; // foo 推断为 number 类型
let bar = "hello"; // bar 推断为 string 类型
let baz = true; // baz 推断为 boolean 类型

在上述示例中,变量的类型是根据其初始值的类型自动推断出来的。这减少了手动指定类型的冗余,并且在代码编写时提供了一定的类型安全性。

类型断言(Type Assertion)也被称为类型转换。它允许开发者手动指定变量的类型,即使 TypeScript 的类型推断机制可能得出不同的类型。通过类型断言,我们可以告诉编译器我们比它更了解变量的类型。

类型断言有两种形式:

  1. 使用尖括号(<类型>)语法:
let value: any = "hello";
let length: number = (<string>value).length;

在这个例子中,我们告诉编译器变量 value 是一个 any 类型,但我们确切知道它是一个字符串。通过类型断言 <string>,我们可以访问字符串类型的 length 属性。

  1. 使用 “as” 关键字:
let value: any = "hello";
let length: number = (value as string).length;

这种方式与尖括号语法相同,只是使用了 as 关键字进行类型断言。

需要注意的是,类型断言并不会进行类型转换或运行时的类型检查,它只是在编译时告诉编译器使用指定的类型。

14.现有一个JS项目,你该如何把JS项目升级为TS项目,你有什么想法。

  1. 初始化 TypeScript 项目:通过在项目根目录中运行 npm init 命令初始化一个新的 TypeScript 项目。这将创建一个 package.json 文件来管理项目依赖和配置。
  2. 安装 TypeScript:使用 npm install typescript --save-dev 命令安装 TypeScript 作为项目的开发依赖。
  3. 创建 tsconfig.json 文件:在项目根目录创建一个名为 tsconfig.json 的文件来配置 TypeScript 项目。可以手动创建或运行 npx tsc --init 命令自动生成该文件,并根据需要进行适当的配置。例如,可以指定输出目录、启用的编译选项等。
  4. 重命名 JavaScript 文件为 TypeScript 文件:将 JavaScript 文件的扩展名从 .js 改为 .ts 或 .tsx(如果使用 JSX)。
  5. 逐步迁移:根据项目规模和复杂性,可以逐步将 JavaScript 文件中的代码转换为 TypeScript。可以从顶层开始,一次转换一个文件,然后检查编译器报告的错误,并逐步修复这些错误。
  6. 类型注解和类型定义:为代码添加类型注解,这是 TypeScript 的主要特性之一。通过为变量、函数参数、返回值等添加类型注解,可以提供更好的类型安全性和代码理解性。
  7. 类型定义文件:如果项目依赖于第三方 JavaScript 库,需要为这些库编写或找到相应的类型定义文件(.d.ts 文件),以便在 TypeScript 项目中正确引用和使用这些库。
  8. 编译 TypeScript 代码:使用 TypeScript 编译器(TSC)编译 TypeScript 代码。可以在终端中运行 npx tsc 命令来编译项目。根据 tsconfig.json 中的配置,编译后的 JavaScript 文件将输出到指定的目录中。
  9. 解决编译错误:在编译 TypeScript 代码时,可能会遇到一些错误和警告。根据编译器的报告,解决这些错误和警告,并确保项目能够成功编译。
  10. 测试和调试:在项目升级完成后,进行测试和调试,确保功能的正确性和稳定性。

15.谈谈你对ts中的装饰器的理解

在 TypeScript 中,装饰器(Decorators)是一种特殊的语法,用于修改类、方法、属性或参数的行为。装饰器可以在不修改源代码的情况下,通过在它们上方应用装饰器来扩展或修改它们的功能。

装饰器使用 @ 符号紧跟在要修饰的目标之前,并可以接受一些参数。装饰器可以应用于类、类的属性、类的方法以及方法的参数上。

其中装饰器分为类装饰器 方法装饰器 属性装饰器 参数装饰器

16.declare关键字有什么作用?

在TypeScript中,declare关键字用于声明一个全局变量、函数、对象或模块的类型,告诉编译器这些实体已经存在,不需要进行编译时的检查。

declare关键字通常用于与JavaScript代码进行整合,特别是在引入第三方库或外部模块时,因为这些库的类型定义可能不存在或不完善。

通过使用declare关键字,可以提供对外部实体的类型声明,以便在编译时避免类型错误,并且可以获得代码编辑器的智能提示和自动补全功能。

以下是一些使用declare关键字的示例:

  1. 全局变量声明:
declare const myGlobalVar: string;
  1. 函数声明:
declare function myFunction(arg1: number, arg2: string): boolean;
  1. 对象声明:
declare namespace myNamespace {
  const myProperty: number;
  function myMethod(): void;
}
  1. 模块声明:
declare module 'myModule' {
  export function myFunction(): void;
}

请注意,使用declare关键字只会在类型层面上提供声明,并不会在运行时创建变量或函数。因此,确保在使用declare声明外部实体时,确实存在该实体的实现或库文件。