30 个前端面试问题 - TypeScript
TypeScript是现代前端开发者的核心技能之一。掌握它不仅包括基本语法,还包括更深层次的概念,例如类型、接口、泛型以及 TypeScript 如何与 JavaScript 库交互。以下是一份精心挑选的30 个针对前端开发者职位的面试问题清单,重点关注 TypeScript。
TypeScript 基本语法和特性
1. TypeScript 和 JavaScript 之间的主要区别是什么?
- TypeScript是 JavaScript 的静态类型超集。它添加了 JavaScript 所缺乏的类型、接口和编译时类型检查。TypeScript 可以转换为纯 JavaScript,使其与任何 JavaScript 环境兼容。
2.为什么我们需要 TypeScript?
- TypeScript 有助于在编译时捕获错误,提供更好的工具(自动完成、重构),并通过执行严格的类型规则确保代码更易于维护和可扩展。
3. TypeScript 中有哪些类型?
- TypeScript支持原始类型,例如
string
、、、、、、和number
。它还支持复杂类型boolean
,例如、、、、、、、、和和类型。undefined
null
symbol
bigint
arrays
tuples
enums
any
unknown
void
never
objects
union
intersection
type
4.和有什么区别interface
?
type
两者interface
都允许您定义自定义类型,但interface
更适合定义对象的形状,同时type
可以处理更复杂的类型,例如联合和元组。
type CustomType = string | number;
interface User {
id: number;
name: string;
}
5. 您如何看待 JSDoc 作为 TypeScript 的替代品?
- JSDoc 是一个可以注释 JavaScript 类型的文档工具,但它不提供与 TypeScript 相同的编译时安全性。JSDoc 缺少 TypeScript 的许多功能,例如静态分析(它可以确保代码在执行前正确性)。
6. TypeScript 中的联合类型是什么?请举例说明。
- 联合类型允许一个值属于多种类型之一。它使用
|
运算符来组合类型。
function printId(id: number | string) {
console.log(id);
}
7. TypeScript 如何处理类型断言?为什么要使用as
?
- 类型断言(使用
as
尖括号语法)会告诉 TypeScript 编译器,你比它更了解该类型。当你确定类型但 TypeScript 无法正确推断时,就会使用类型断言。
const value: any = "Hello";
const strLength: number = (value as string).length;
unknown
8.和类型之间有什么区别any
?
unknown
比 更安全any
。虽然any
禁用所有类型检查,但unknown
强制您在操作值之前执行类型检查。
let data: unknown;
data = "Hello";
if (typeof data === "string") {
console.log(data.toUpperCase());
}
9. 它是什么never
类型,什么时候使用它?
- 该
never
类型表示永远不会发生的值。它通常用于抛出错误或无限循环的函数。
function throwError(): never {
throw new Error("This is an error");
}
10.什么是类型缩小,TypeScript 如何实现它?
typeof
当 TypeScript 使用类型保护(例如或instanceof
)将变量的类型简化为更具体的类型时,就会发生类型缩小。
function padLeft(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);
}
13. 描述条件类型以及何时可以使用它们。
- 条件类型允许您创建依赖于条件的类型,从而实现高级类型操作。
type IsString<T> = T extends string ? true : false;
Partial<T>
14. 实用程序类型和有什么区别Pick<T, K>
?
Partial<T>
使中的所有属性T
成为可选的。Pick<T, K>
从中提取特定的属性T
。
interface Person {
name: string;
age: number;
}
type PartialPerson = Partial<Person>;
type NameOnly = Pick<Person, 'name'>;
15. 在 TypeScript 中, 做什么keyof
?
keyof
创建对象类型的键的联合。
interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // 'name' | 'age'
16. 如何使用可区分联合来实现类型安全的错误处理?
- 判别联合允许您使用通用判别属性以安全的方式处理不同类型。
type Success = { status: "success"; data: string };
type Failure = { status: "failure"; error: string };
type Response = Success | Failure;
function handleResponse(response: Response) {
if (response.status === "success") {
console.log(response.data);
} else {
console.log(response.error);
}
}
17.什么是模板文字类型,它们有多有用?
- 模板文字类型允许您通过组合字符串文字的联合来创建新的字符串类型,从而增加了使用字符串类型的灵活性。
type Greeting = `Hello, ${string}!`;
TypeScript 和 OOP(面向对象编程)
18. TypeScript 如何使用类?它们与 ES6 类有何不同?
- TypeScript 类通过附加类型注释、访问修饰符和接口扩展了 ES6 类。
class Person {
private name: string;
constructor(name: string) {
this.name = name;
}
getName(): string {
return this.name;
}
}
19. TypeScript 中的访问修饰符(public、private、protected)是什么?
- 访问修饰符控制属性和方法的可见性。表示在类内、类和子类内
public
随处可访问。private
protected
20. 抽象类在 TypeScript 中如何工作,以及何时应该使用它们?
- 抽象类定义功能不完整的基类,强制子类实现特定的方法。
abstract class Animal {
abstract sound(): void;
move() {
console.log("Moving...");
}
}
class Dog extends Animal {
sound() {
console.log("Woof!");
}
}
21. 接口和抽象类有什么区别?
- 接口定义了一个契约(结构),但没有任何实现,而抽象类可以定义抽象方法和具体方法。
22. 如何描述我们在函数内部创建并在函数外部返回的 TypeScript 类?
- 您可以从函数内部创建并返回一个类来提供封装。
function createUser() {
return class User {
constructor(public name: string) {}
};
}
const UserClass = createUser();
const user = new UserClass("John");
React 中的 TypeScript
23. 如何使用 TypeScript 定义 React 组件的 props 和 state 的类型?
- 您可以使用接口或类型定义道具和状态。
interface Props {
title: string;
}
interface State {
count: number;
}
class MyComponent extends React.Component<Props, State> {
state: State = { count: 0 };
render() {
return <div>{this.props.title}</div>;
}
}
- 要使用 TypeScript在React 函数式组件中定义 props 和 state 的类型,你也可以使用
interface
或type
。由于函数式组件不像类组件那样拥有内部状态,因此你可以直接为 props 指定类型。但是,对于由类似 的钩子管理的状态useState
,你也可以指定它们的类型。
// Define the props type
interface Props {
title: string;
}
const MyFunctionalComponent: React.FC<Props> = ({ title }) => {
// Define the state with useState and give it a type
const [count, setCount] = React.useState<number>(0);
return (
<div>
<h1>{title}</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
24.在 React 组件中使用interface
vs的 props有什么区别?type
- 两者都很常用,但
interface
可扩展,使其更适合道具组合,同时type
可以处理更复杂的联合。
25.如何使用 TypeScript 编写钩子类型?
- 直接使用类型来挂钩。
const [count, setCount] = useState<number>(0);
JSX.Element
26.和有什么区别React.ReactNode
?
JSX.Element
指的是组件返回的 React 元素,而React.ReactNode
包括 React 可渲染的任何内容,如字符串、数字或片段。
27. 如何在 TypeScript 中输入自定义钩子?
- 必要时,可以使用泛型来输入自定义钩子。
function useCustomHook<T>(initialValue: T): [T, (value: T) => void] {
const [state, setState] = useState(initialValue);
return [state, setState];
}
大型项目中的 TypeScript
28. 在大型 TypeScript 项目中,如何管理跨多个文件的复杂类型?
- 使用 TypeScript 的模块系统将类型拆分到各个文件,并在需要时导入。
index.ts
这样可以更好地导出类型。
// types.ts
export interface User {
id: number;
name: string;
}
// index.ts
export * from './types';
29. TypeScript 中的函数式编程与其他语言中的方法有何不同?
- TypeScript 通过支持高阶函数、不变性和强类型推断来实现函数式编程,类似于 Haskell 或 Scala 等语言,但保留了 JavaScript 的灵活性。
30. 使用 TypeScript 中的外部服务或 REST API 时,如何确保类型安全?
- 您可以使用 TypeScript 的类型系统来定义预期的 API 响应形状,并在使用外部数据时验证类型。
interface ApiResponse {
userId: number;
id: number;
title: string;
}
async function fetchPost(id: number): Promise<ApiResponse> {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${id}`);
return response.json();
}
准备这些问题、研究所涉及的主题以及查看相关资源可以提高您成功通过面试的机会。
我期待您的反应和评论。💬
祝您面试顺利!🌟