在当今的 Web 开发世界中,TypeScript 作为一种强大的工具为自己赢得了一席之地,它弥补了 JavaScript 的灵活性和静态类型语言的鲁棒性之间的差距(至少在 JavaScript 实现自己的类型之前)。
随着技术格局的不断发展,对 TypeScript 开发人员的需求也在不断增加,技能要求也有所提升,但如何在面试中让自己脱颖而出呢? 又或者你是一名面试官,你正在招聘 TypeScript开发人员,那如何确保您的候选人真正掌握 TypeScript?
然后,让我们深入研究这个神奇的列表,其中,包含 30 个富有洞察力的 TypeScript 问题,范围从基础知识到更高级(分为 25 个针对中级角色,5 个针对更高级角色)
01、什么是 TypeScript?为什么使用它比普通 JavaScript 更有优势?
答案:TypeScript 是 JavaScript 的静态类型超集,可以编译为纯 JavaScript。通过引入静态类型,它允许开发人员在编译时而不是运行时捕获与类型相关的错误。
这可以减少错误,提高代码可读性,并通过增强的工具(例如自动完成和代码导航)提供更高效的开发体验。
02、TypeScript 中的any类型和unknown类型有何不同?
答案:any 和unknown 都代表 TypeScript 中的任何值。
但有一个关键的区别:any 绕过了编译器的类型检查,本质上关闭了 TypeScript 对该变量的好处。
另一方面,unknown 保持类型检查完整,确保在对变量执行操作之前断言或缩小变量的类型。
03、在什么场景下你会使用自定义类型,它们在 TypeScript 中是如何定义的?
答案:当我们有复杂的结构或重复的模式时,使用 type 关键字或接口定义的自定义类型是有益的。
例如,如果我们经常处理用户数据,我们可以定义一次用户类型或接口,然后在整个代码库中使用它,而不是在函数或类中重复定义用户的形状。
04、工会类型有哪些?它们有何益处?
答案:联合类型是一种表示一个值可以属于多种类型之一的方式。例如,如果函数接受字符串和数字作为参数,则可以将其键入为 function example(arg: string | number)。这确保了功能的灵活性,同时,仍然保持类型安全。
05、Type Guards 如何增强 TypeScript 的功能?
答案:类型保护是运行时检查,有助于缩小条件块中变量的类型范围。它们允许函数和方法根据输入类型表现不同,而不会丢失类型信息。常见的类型保护包括使用 typeof、instanceof 和用户定义的类型保护函数。
06、TypeScript 中元组与常规数组的区别是什么?
答案:TypeScript 中的元组是一个数组,其中元素的类型、顺序和数量已知。例如,[string, number] 元组类型期望第一个元素是字符串,第二个元素是数字。这与常规数组形成对比,常规数组只知道元素的类型,而不知道顺序或计数。
07、在 TypeScript 中将属性标记为可选时,使用什么语法?你为什么要这样做?
答案:在 TypeScript 中,? 符号用于将属性标记为可选,例如 name?: string。当创建可能缺少值的结构或处理来自外部源的数据(其中某些字段可能不存在)时,这非常有用。
08、在定义对象形状时,您能区分interface和type吗?
答:interface和type都可以定义对象形状,但是它们有一些区别。interface更具可扩展性,允许声明合并。type 提供了更多的多功能性,能够表示并集、交集、元组等。虽然interface主要用于对象形状,但 type 可以捕获更广泛的模式。
09、为什么泛型在 TypeScript 中至关重要?它们如何发挥作用?
答:泛型允许创建灵活且可重用的组件,而无需牺牲类型安全性。它们充当未来类型的占位符,让您可以编写适用于多种类型的函数、类或接口。通过利用泛型,开发人员可以确保各种数据的类型安全,而无需编写冗余代码。
10、readonly 关键字如何改变 TypeScript 变量或属性?
答案:readonly 关键字当作为变量或属性的前缀时,可确保一旦设置其值,此后就无法修改。它对于确保在使用配置对象或在组件或函数之间传递数据等场景中的不变性特别有用。
11、TypeScript 中的可区分联合有什么用处?
答案:可区分联合(也称为标记联合)是一种结合了联合类型、文字类型和类型保护的模式。
当一个对象可以有多个形状但共享一个公共属性(通常是文字类型)时,可以使用它们,该属性可用于缩小其确切形状。
公共属性(通常称为“鉴别器”)允许我们在联合内的类型之间安全地切换,从而更轻松地使用此类对象。
12、继承在 TypeScript 中如何发挥作用?
答案:TypeScript 支持继承,就像 ES6 类一样。使用extends关键字,一个类可以继承另一个类的属性和方法,提高代码的可重用性并建立基类和派生类之间的关系。派生类还可以重写继承的方法或属性,甚至用新的方法或属性扩展对象结构。
13、装饰器在 TypeScript 中扮演什么角色?
答:装饰器受到 Python 和 Java 等语言中注释的启发,提供了一种添加元数据或修改类定义、方法、属性或方法参数的方法。
装饰器使用 @ 前缀,可以影响或扩展它们装饰的元素的行为,使其成为解决依赖注入、日志记录甚至装饰器等设计模式(模式,而不是功能本身)等问题的强大工具。
14、在 TypeScript 中,比较运算符 == 和 === 有什么不同?
答案:与 JavaScript 一样,== 是一个执行类型强制的松散相等运算符,这意味着如果不同类型的值在强制转换后具有相同的值,则可以将它们视为相等。
另一方面, === 是一个严格的相等运算符,它检查值和类型,使其在类型敏感的上下文中更安全、更可预测。
15、如何在 TypeScript 中声明只读数组,以及为什么要使用它?
答案:在 TypeScript 中,您可以使用 readonly 修饰符后跟数组类型来定义只读数组,例如 readonly string[]。
使用只读数组可确保数组在创建后无法修改,这对于确保数据不变性特别有用,例如在函数或组件之间传递数据时。
16、TypeScript 中的 never 类型意味着什么?
答案:TypeScript 中的 never 类型表示永远不会出现的值。它通常用于不返回值的函数 - 例如,那些总是抛出异常或具有无限循环的函数。它通过指示不应或无法到达某个代码路径来帮助确保类型安全。
17、如何将 TypeScript 与 React 这样的框架集成?
答:要将 TypeScript 与 React 集成,可以使用 .tsx(TypeScript 与 JSX)文件。对于组件属性和状态,可以定义 TypeScript 接口或类型。
React.FC 泛型类型通常用于定义功能组件的类型,为 props、默认 props 和其他 React 特定功能提供强类型。
18、命名空间在 TypeScript 中起什么作用,它们仍然相关吗?
答案:TypeScript 中的命名空间是一种对相关代码进行分组的方法,它们有助于避免全局命名空间中的命名冲突。
然而,随着 ES6 模块的兴起,它提供了一种更加标准化和精细的方式来组织和封装代码,命名空间的相关性在许多现代 TypeScript 项目中已经减弱。
19、如何在 TypeScript 中使用类型断言?何时需要它?
答案:TypeScript 中的类型断言是一种告诉编译器将变量视为某种类型的方法。这就像其他语言中的类型转换。语法可以是
20、描述 TypeScript 中索引签名的用途和语法。
答案:TypeScript 中的索引签名允许对象具有某种类型的动态属性。语法通常类似于 { [key: string]: ValueType }。当您事先不知道对象的键但知道其值的类型时,这是很有用的。
21、TypeScript 如何处理可选链接和 nullish 合并?
答案:TypeScript 支持可选链接 (?.),它允许读取位于连接对象链深处的属性值,而无需检查链中的每个引用是否有效。如果任何引用为 null 或未定义,则表达式会与未定义的值短路。
空合并运算符 (??) 是一个逻辑运算符,当其左侧操作数为空或未定义时返回其右侧操作数,否则返回其左侧操作数。这在您想要回退到默认值的情况下非常有用。
22、什么是映射类型,以及如何在 TypeScript 中使用它们?
答案:映射类型允许通过转换属性在现有类型的基础上创建新类型。它们遵循一种模式,您可以在其中迭代对象类型的属性并生成新类型。常见用途包括使用 Partial
23、您将如何在 TypeScript 中创建和使用 mixin?
答案:Mixin 是一种从可重用组件创建类的模式。在 TypeScript 中,mixin 可以通过创建接受类并使用新属性或方法扩展它的函数来实现。然后,可以组合这些函数来装饰或扩充类。此模式允许在 TypeScript 中实现类似多重继承的行为。
24、TypeScript 中方法重载和函数重载有什么区别?
答案:TypeScript 支持函数重载,即为单个函数声明多个函数类型。然后,编译器将根据函数调用的参数使用适当的类型。但是,TypeScript 不支持传统的方法重载(您可以定义多个具有相同名称但参数不同的方法)。
相反,您可以使用可选参数或联合类型来实现类似的功能。
25、装饰器如何影响 TypeScript 的类属性和方法?
答:装饰器是作为 JavaScript 提案引入的,是可用于修改或扩展类属性、方法等的特殊函数。在 TypeScript 中,当装饰器应用于类成员时,它们会提供元数据或更改被装饰元素的行为。它们可用于各种任务,例如日志记录、验证或增强功能。
接下来,这几道面试题是针对高级 TypeScript 开发人员的问题,有兴趣的小伙伴可以继续阅读。
26、描述 TypeScript 的类型推断机制如何工作。
答:TypeScript 的类型推断是指编译器在没有显式类型注释的情况下自动推断和分配类型的能力。虽然鼓励显式类型,但编译器会尽可能使用上下文(如变量初始化、返回语句等)来推断类型。上下文输入等功能有助于函数表达式等场景。
27、什么是类型防护,如何创建自定义类型防护?
答案:类型保护是执行运行时检查并缩小条件块内类型范围的表达式。常见的类型保护包括 typeof 和 instanceof。自定义类型保护是一个函数,其返回类型是使用 is 关键字缩小类型的类型谓词,例如 function isFish(pet: Fish | Bird): pet is Fish。
28、讨论 TypeScript 中声明合并的工作原理。
答:声明合并是指编译器将多个同名的声明合并到一个定义中。此功能对于接口非常强大:如果多次定义一个接口,TypeScript 会将其视为具有组合成员的单个接口。这在扩展现有类型或使用模块化代码时非常有用。
29、如何利用 TypeScript 中的条件类型?
答案:条件类型允许根据条件以更动态的方式表达类型。它们遵循 T 延伸 U ?X : Y,这意味着如果类型 T 可分配给 U,则类型为 X,否则为 Y。这使得基于类型之间的关系可以进行更灵活的类型操作。
30、解释在高级类型场景中如何以及为何使用 keyof 和 typeof 运算符。
答案:keyof 运算符生成给定类型的已知公共属性名称的并集,这对于限制可能的字符串值或创建映射类型很有用。typeof 运算符在类型上下文中使用时,获取变量、常量或对象文字的类型,这对于基于现有对象的形状创建类型非常有用,而无需手动重复其结构。