TypeScript 是现代前端开发者的的核心技能之一。精通它不仅包括基本语法,还包括更深入的概念,比如类型、接口和泛型,以及如何将 TypeScript 与 JavaScript 库进行交互。以下是专门针对前端开发者 TypeScript 技能的 30 道精选面试题目。
TypeScript 的基本语法和特性
1. TypeScript 和 JavaScript 有什么不同?
- TypeScript 是一种静态类型检查的 JavaScript 超集。它增加了类型、接口和编译时类型检查,而这些都是 JavaScript 没有的。TypeScript 会编译成普通的 JavaScript,因此可以在任何 JavaScript 环境中运行。
我们为什么需要 TypeScript?
- TypeScript 在编译阶段帮助捕获错误,提供更好的工具(如自动完成功能和重构),并通过强制实施严格的类型检查来确保代码更易于维护和扩展。
3. TypeScript 有哪些类型呢?
- TypeScript 支持诸如
string
、number
、boolean
、undefined
、null
、symbol
和大整数
这样的原始类型。它还支持诸如array
、tuple
、enum
、any
、unknown
、void
、never
、object
,以及联合类型
和交集类型
。
4. 你知道吗,type
和interface
两者之间有何不同?
大家知道type
和interface
之间有何不同吗?
type
和interface
都可以定义自定义类型,而interface
更适合定义对象的结构,而type
更适合处理更复杂的类型,比如联合和元组。
type 自定义类型值 = string | number;
interface 用户接口 {
id: number;
name: string;
}
切换到全屏模式 退出全屏模式,回到正常视图
你认为JSDoc可以作为TypeScript的替代方案吗?
- JSDoc 是一个可以为 JavaScript 标记类型的文档工具,但没有 TypeScript 那样的编译时安全性。JSDoc 缺少许多 TypeScript 的功能,例如静态检查,无法确保代码在执行前的正确性。
6. TypeScript 中的联合类型是什么样的?举个例子。
- 联合类型(union类型)允许一个值可以是多种类型之一。它使用
|
符号来组合不同类型。
// 此函数接收一个参数,该参数可以是数字或字符串,并将其打印到控制台。
function printId(id: number | string) {
console.log(id);
}
点击全屏,点击退出全屏
7. TypeScript是如何处理类型断定的?为什么我们应该用as
?
- 类型断言(使用
as
或尖括号语法)告诉 TypeScript 编译器你更了解类型。当你确定类型但 TypeScript 无法正确推断类型时,可以使用类型断言。
const 值: any = "你好";
const 字符串长度: number = (值 as string).length;
// 获取字符串的长度
全屏;退出全屏
unknown
和any
类型有什么不同?
unknown
比any
更安全,因为虽然any
禁用所有类型检查,unknown
则强制你在使用值之前做类型检查。
声明一个未知类型的变量data;
data赋值为"Hello";
如果类型检查data是“字符串”,{
输出data.toUpperCase()的结果;
}
全屏模式,退出全屏
9. 什么是never
类型,什么时候会使用它?
never
类型表示永远不会出现的值类型。它常用于抛出错误的函数或无限循环中。
function throwError(): void {
throw new Error("这是一个错误");
}
进入全屏;退出全屏
10. 什么是类型缩减,TypeScript 如何实现这一点?
- 类型缩减现象发生在通过类型守卫(例如
typeof
或instanceof
)将变量类型缩小到更具体类型时的 TypeScript 中。
function 左填充(value: string | number) {
// 左填充函数,用于在字符串或数字的左侧填充到指定长度
if (typeof value === "string") {
return value.padStart(10);
}
return value.toString();
}
进入全屏模式,退出全屏状态
高级类型功能
11. TypeScript中的泛型是什么,它们是如何帮助实现代码的再利用的?
- 泛型允许你创建可复用的组件或函数,这些组件或函数可以处理任意类型的数据,从而提供灵活性和类型安全。
// 返回参数的恒等函数
function identity<T>(arg: T): T {
return arg;
}
全屏模式,退出全屏
12. 泛型约束是怎么工作的?为什么它们这么有用?
你可以把泛型限制为必须满足特定条件,比如具有某些特定属性。
function logLength<T extends { length: number }>(arg: T): void {
console.log(arg.length);
}
定义了一个名为logLength
的函数,该函数接收一个泛型类型参数T
,该类型需要有一个length
属性,其值为数字。函数执行后会打印出传入参数的length
属性值。
全屏开启/退出全屏
描述不同条件类型,并说明它们在什么情况下可以被使用。
- 根据条件的类型允许你创建特定的类型,从而实现更复杂的类型处理。
type IsString<T> = T extends string ? true : false;
切换到全屏 退出全屏
14. 你了解 Partial<T>
和 Pick<T, K>
之间有什么不同吗?
Partial<T>
使T
中的所有属性都变成可选的。Pick<T, K>
从T
中提取特定的属性。
接口 Person {
name: 字符串;
age: 数字;
}
类型 PartialPerson = 部分<Person>;
类型 NameOnly = 只取<Person, 'name'>;
全屏,退出全屏
15. 在 TypeScript 中,keyof
是什么?
keyof
生成一个对象类型键的联合,也就是创建一个该对象类型所有键的结合。
interface Person {
name: 姓名;
age: number;
}
// 这个类型表示 Person 接口的键,可以是 '姓名' 或 'age'
type PersonKeys = keyof Person; // 可以是 '姓名' 或 'age'
全屏 退出全屏
16. 你如何处理类型安全的错误处理,特别是在使用鉴别联合时?
- 标签联合允许你以一种安全的方式处理不同类型,使用一个共同的标签属性。
type 成功 = { 状态: "成功"; 数据: string };
type 失败 = { 状态: "失败"; 错误: string };
type 响应 = 成功 | 失败;
function 处理响应(响应: 响应) {
if (响应.状态 === "成功") {
console.log(响应.数据);
} else {
console.log(响应.错误);
}
}
// 处理响应函数用于根据响应状态打印数据或错误信息
切换到全屏 切换回正常模式
17. 模板字面类型是什么玩意儿,它们有多大的用处?
- 模板字面字符串类型允许你通过组合字符串字面量来创建新的字符串类型,从而在处理字符串类型时提供更大的灵活性。
类型定义 Greeting = `你好,${字符串}!`;
点击这里全屏模式。点击这里退出全屏
TypeScript与面向对象编程 (OOP)
18. TypeScript如何使用类呢?,TypeScript类和ES6类有什么区别呢?
- TypeScript 类在 ES6 类的基础上增加了类型注解、访问控制符和接口。
/**
* 一个表示人的类
*/
class Person {
/**
* 人的名字
*/
private name: string;
/**
* 构造函数,用于初始化名字
* @param name 人的名字
*/
constructor(name: string) {
this.name = name;
}
/**
* 获取名字的方法
* @returns 返回人的名字
*/
getName(): string {
return this.name;
}
}
点击进入全屏,再点击退出
19. 在 TypeScript 中,public、private 和 protected 是什么访问修饰符?
- 访问修饰符用来控制属性和方法的可见性。
public
表示可以从任何地方访问。private
表示只能在类内部访问。protected
表示可以在类及其子类中访问。
20. TypeScript中的抽象类是如何工作的,什么时候该用抽象类?
- 抽象基类定义了基础类,但留下了未实现的功能,需要子类来完成特定方法的实现。
abstract class 动物 {
abstract 喇叭(): void;
移动() {
console.log("正在移动...");
}
}
class 狗 extends 动物类 {
喇叭() {
console.log("汪汪!");
}
}
全屏 全屏退出
21. 接口和抽象类有什么区别?
接口仅定义约定而不提供具体实现,而抽象类则可以同时定义抽象方法和具体方法。
我们在函数内部创建并在外部返回的 TypeScript 类,应该如何描述这种类型的类?
- 你可以在函数内部创建一个类并在内部返回它,从而实现封装。
函数创建用户() {
返回类 用户 {
构造函数(public 名称: 字符串) {}
};
}
常量 用户类 = 创建用户();
常量 用户 = 新 用户类("John");
// 函数创建用户定义了一个生成用户类的函数。
// 类用户定义了一个带有公共属性名称的构造函数。
// 常量用户类调用了创建用户函数来获取用户类。
// 新关键字用于实例化用户类并传入名称"John"。
进入全屏 退出全屏
TypeScript 和 React
23. 你如何在使用 TypeScript 时为 React 组件的 props 和 state 定义类型?
你可以用接口或类型来定义props和state。
接口 Props 接口 {
title: string;
}
接口 State 接口 {
count: number;
}
类 MyComponent extends React.Component<Props, State> {
state: State = { count: 0 };
render() {
return <div>{this.props.title}</div>;
}
}
点击全屏,点击退出全屏
- 在使用 TypeScript 定义 函数式 React 组件 的类型时,在定义 props 和状态时,你可以使用
interface
或type
关键字。因为函数组件没有内部状态,直接为 props 定义类型即可。然而,对于通过useState
这样的 hook 管理的状态,也可以为这些状态定义类型。
// 定义 props 类型
interface Props {
title: string;
}
// 定义名为 MyFunctionalComponent 的函数组件,并使用 React.FC 作为类型
const MyFunctionalComponent: React.FC<Props> = ({ title }) => {
// 使用 useState 定义状态,并指定类型
const [count, setCount] = React.useState<number>(0);
return (
<div>
<h1>{title}</h1>
<p>当前计数: {count}</p>
<button onClick={() => setCount(count + 1)}>加一</button>
</div>
);
};
退出全屏 进入全屏
在 React 组件中,使用 interface
还是 type
来定义 props 有什么区别呢?
- 这两个都常被使用,但
interface
是可扩展的,因此更适合进行属性组合,而type
可以处理更复杂的联合。
你如何用 TypeScript 编写钩子函数?
- 直接将类型绑定到钩子。
const [count, setCount] = useState<number>(0);
进入全屏 退出全屏
26. “JSX.Element”(JSX元素)和“React.ReactNode”(React的ReactNode)有什么区别?
JSX.Element
指由组件返回的 React 元素,而React.ReactNode
则可以是任何 React 能渲染的对象,比如字符串、数字或片段。
- 如何在 TypeScript 中创建自定义钩子?
- 自定义钩子在必要时使用泛型定义类型。
定义一个名为 useCustomHook
的泛型函数,它接受一个初始值 initialValue
作为参数,并返回一个状态值和一个更新状态的方法。具体来说,该函数通过 useState
钩子初始化状态,然后返回当前状态和更新状态的函数。
全屏 退出全屏
大型项目中的 TypeScript
28. 在大型 TypeScript 项目中,你如何处理多个文件中的复杂类型?
- 使用 TypeScript 的模块系统将类型拆分到不同文件中,并在需要时导入它们。您可以使用
index.ts
来更好地导出这些类型。
// 用户定义文件
// types.ts
export interface User {
id: number;
name: string;
}
// 导入用户定义
// index.ts
export * from './types';
全屏 退出全屏
29. TypeScript 中的函数式编程与其他语言中的函数式编程有何不同?
- TypeScript 支持函数式编程,通过支持高阶函数、不可变性(Immutability)以及强大的类型推断,从而支持了函数式编程,类似于像 Haskell 或 Scala 这样的语言,同时也保留了 JavaScript 的灵活性。
30. 在使用外部服务或 REST API 时,你是怎么确保类型安全性的?
你可以使用 TypeScript 的类型系统来定义预期的数据类型,并在处理外部数据时进行验证。
接口 ApiResponse {
userId: 数字;
id: 数字;
title: 字符串;
}
// 获取帖子的异步函数,参数为帖子ID
async function 获取帖子(id: 数字): Promise<ApiResponse> {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
// 等待获取响应
return response.json();
// 返回解析后的 JSON 数据
}
全屏 退出全屏
zh: ……
(Note: The ellipsis "……" is used in Chinese to represent omitted or unspecified content, similar to " *" in English.)
为这些问题做好准备,研究相关主题,并查阅相关资料可以提高你成功通过面试的几率。
我期待大家的回复和评论。💬
祝你面试顺利!🌟