Level 1:基础(Junior)

Level 2:React 开发(Mid)

Level 3:Next.js 实战(Senior)

Level 4:TypeScript 高级(Senior+)

Level 5:架构级(Staff)

第一部分(基础篇)

 

Q1. What is the difference between type and interface?

中文:

typeinterface 有什么区别?什么时候应该使用它们?

English Answer

Both type and interface can describe the shape of an object, and in many cases they are interchangeable.

The main difference is that interface is designed for object-oriented style and supports declaration merging, while type is more flexible because it can represent unions, intersections, tuples, primitive aliases, and function types.

In React projects, I usually use interface for component props or object structures, and type for utility types, unions, mapped types, and conditional types.

中文答案

typeinterface 都可以描述对象结构,大多数情况下可以互换。

主要区别是:

实际项目中:

面试加分回答

Although both work for object types, I prefer using interface for public object contracts and type for advanced type compositions because it keeps the code more consistent and readable.

 

Q2. What is the difference between any and unknown?

中文:

anyunknown 有什么区别?

English Answer

any completely disables type checking. Once a value is typed as any, TypeScript won't perform any compile-time validation, which can easily introduce runtime bugs.

unknown is a safer alternative. It accepts any value, but before using it, we must narrow its type with checks such as typeof, instanceof, or custom type guards.

In production projects, I avoid using any unless absolutely necessary and prefer unknown when dealing with external data such as API responses or user input.

中文答案

any 会直接关闭 TypeScript 类型检查。

任何操作都会通过编译。

unknown 更安全。

虽然可以接受任何值,但是必须先进行类型缩小(Type Narrowing)才能使用。

例如:

生产环境中,应尽量避免 any,对于接口数据或用户输入,更推荐使用 unknown

面试加分回答

unknown forces developers to validate data before using it, which makes applications much safer when handling external or untrusted data.

 

Q3. What is Generic?

中文:

什么是泛型?为什么要使用泛型?

English Answer

Generics allow us to write reusable and type-safe code without knowing the exact type in advance.

Instead of using any, we define a type parameter that will be inferred when the function or component is used.

This improves both flexibility and type safety.

React heavily relies on generics, such as useState, useRef, and reusable components.

中文答案

泛型可以让代码既保持通用性,又保证类型安全。

它不会像 any 一样丢失类型信息,而是在使用时由 TypeScript 自动推导具体类型。

React 中大量使用泛型,例如:

面试加分回答

Generics allow us to write reusable components and utility functions while preserving precise type information, making large codebases much easier to maintain.

 

Q4. Why is Type Inference important?

中文:

TypeScript 为什么要做类型推导?

English Answer

Type inference allows TypeScript to automatically determine types without requiring explicit annotations everywhere.

It keeps the code cleaner while still providing autocomplete, compile-time checking, and refactoring support.

I usually rely on inference whenever the type is obvious, and only add explicit annotations when they improve readability or define public APIs.

中文答案

类型推导可以减少大量重复的类型声明。

TypeScript 会根据变量初始值、函数返回值和上下文自动推断类型。

这样既能保持代码简洁,也不会失去类型检查能力。

一般来说,当类型很明显时,我会依赖类型推导;只有在公共接口或复杂逻辑中才显式声明类型。

 

Q5. What is the difference between interface extends and intersection (&)?

中文:

extends& 有什么区别?

English Answer

Both can combine multiple types, but they behave differently.

extends creates a new interface by inheriting another interface and is mainly used in object-oriented designs.

The intersection operator (&) combines multiple types into one and works with any type, including objects, unions, and utility types.

In React projects, I usually use extends for component prop inheritance and & when composing multiple reusable type definitions.

中文答案

二者都可以组合多个类型,但用途不同。

实际项目中:

面试加分回答

extends expresses an inheritance relationship, while & simply merges multiple types together. Choosing the right one makes type definitions clearer and easier to maintain.

 

 

 

 

第二部分:React + TypeScript 高频面试题(中英双语)

这一部分的问题都是 React / Next.js 面试中非常高频的 TypeScript 实战题,比基础语法更贴近真实项目。

 

Q6. How do you define types for React component props?

中文:

React 组件的 Props 应该如何定义类型?

English Answer

In most cases, I define component props using an interface because it clearly describes the public contract of the component.

If the props need to combine multiple reusable types, I may use a type with intersections.

For simple components, either approach works, but consistency across the project is more important than the choice itself.

中文答案

大多数情况下,我会使用 interface 来定义组件的 Props,因为它能够清晰地描述组件的公共接口。

如果需要组合多个已有类型,我会使用 type 配合交叉类型(&)。

对于简单组件,两者都可以,但在团队中保持一致的风格更重要。

面试加分回答

For public component APIs, I prefer using interface because it improves readability and supports declaration merging if needed. For more complex type composition, I use type.

 

Q7. Why is React.FC no longer recommended?

中文:

为什么现在很多项目都不推荐使用 React.FC

English Answer

React.FC was popular in earlier versions of React because it automatically included the children prop.

However, this behavior could make component APIs less explicit, since every component appeared to accept children even when it shouldn't.

Today, most teams prefer defining props directly and only adding children when the component actually needs it.

This makes component interfaces clearer and easier to maintain.

中文答案

以前使用 React.FC 的主要原因是它会自动添加 children 属性。

但是这样会导致所有组件默认都能接收 children,即使实际上并不需要。

现在更推荐直接声明 Props,需要 children 时再显式添加。

这样组件接口更加明确,也更符合 React 当前的推荐实践。

面试加分回答

I avoid React.FC because I prefer explicit component APIs. Only components that actually render children should declare a children prop.

 

Q8. When should you specify the generic type for useState?

中文:

什么时候需要给 useState 指定泛型?

English Answer

TypeScript can usually infer the state type from the initial value.

However, when the initial value is null, undefined, or an empty array or object, inference may not be sufficient.

In those cases, I explicitly provide the generic type to ensure correct type checking throughout the component.

中文答案

如果初始值能够明确推导类型,例如字符串或数字,一般不需要手动指定泛型。

但是以下情况通常需要:

这样可以避免错误的类型推导,提高类型安全。

面试加分回答

I rely on type inference whenever possible, but I explicitly provide generic types when inference is ambiguous or when the state may contain multiple possible types.

 

Q9. Why is the initial value of useRef often null?

中文:

为什么 useRef 通常初始化为 null

English Answer

When a component renders for the first time, the DOM element hasn't been created yet.

React assigns the actual DOM node to the ref after the component has been mounted.

Therefore, null accurately represents the initial state before the DOM becomes available.

中文答案

组件第一次渲染时,DOM 还没有创建。

React 会在组件挂载完成后,把真实 DOM 赋值给 ref.current

因此初始值使用 null 是最准确的表示。

面试加分回答

The ref starts as null because the referenced DOM node doesn't exist during the initial render. React updates it during the commit phase after mounting.

 

Q10. How do you type React event handlers?

中文:

React 中如何给事件定义类型?

English Answer

React provides strongly typed event objects through its Synthetic Event system.

For example:

Using these built-in types provides autocomplete and compile-time safety.

中文答案

React 已经提供了完整的事件类型。

常见的有:

直接使用这些官方类型即可获得完整的类型检查。

面试加分回答

I always use React's built-in event types instead of any, which improves type safety and provides better editor support.

 

Q11. How do you type a generic React component?

中文:

如何编写支持泛型的 React 组件?

English Answer

Generic components allow us to build reusable UI while preserving the type of the data they receive.

A common example is a reusable table component.

Instead of accepting any[], the component accepts a generic type parameter, so TypeScript can infer the row type automatically.

This enables full autocomplete and compile-time validation for columns, render functions, and callbacks.

中文答案

泛型组件可以在保持类型安全的同时,提高组件的复用性。

例如一个 DataTable<T> 组件。

组件并不知道具体的数据类型,而是在使用时由 TypeScript 自动推导。

这样列配置、回调函数和单元格渲染都能获得完整的类型提示。

面试加分回答

Generic components make UI libraries much more scalable because they preserve the caller's data types without sacrificing type safety.

 

Q12. How do you type a custom Hook?

中文:

如何为自定义 Hook 定义类型?

English Answer

A custom Hook should expose a well-defined API.

Its parameters, return values, and callbacks should all be explicitly typed.

If the Hook is reusable across different data models, I usually introduce generics to make it flexible while maintaining strong type safety.

中文答案

自定义 Hook 应该像普通函数一样,明确声明:

如果 Hook 需要支持多种数据类型,可以引入泛型,提高复用性。

面试加分回答

I treat custom Hooks as reusable APIs, so I always define clear input and output types to improve maintainability and developer experience.

 

Q13. How do you type forwardRef?

中文:

forwardRef 应该如何定义类型?

English Answer

When using forwardRef, both the ref type and the component props should be explicitly defined.

The first generic parameter specifies the ref type, while the second defines the props.

This ensures that parent components receive accurate autocomplete and compile-time validation when accessing the forwarded ref.

中文答案

forwardRef 需要同时声明:

这样父组件在访问 ref.current 时,可以获得正确的类型提示和类型检查。

面试加分回答

Explicitly typing both the ref and props makes forwarded components much easier to consume and prevents accidental runtime errors.

 

Q14. What is ComponentProps?

中文:

什么是 ComponentProps

English Answer

ComponentProps extracts the props type from an existing React component.

Instead of redefining the same props manually, we can reuse the existing component's public interface.

This reduces duplication and keeps types synchronized as components evolve.

中文答案

ComponentProps 可以从已有组件中提取 Props 类型。

这样无需重复定义相同的类型,也避免后续组件修改时出现类型不一致的问题。

它是构建可复用组件库时非常常用的工具类型。

面试加分回答

I frequently use ComponentProps when wrapping third-party components, as it keeps my wrapper fully compatible with future API changes.

 

Q15. What are the most common TypeScript mistakes in React projects?

中文:

React 项目中最常见的 TypeScript 使用错误有哪些?

English Answer

Some common mistakes include:

These practices reduce type safety and make code harder to maintain.

中文答案

常见问题包括:

这些都会降低 TypeScript 的价值,并增加维护成本。

面试加分回答

My goal is to let the type system prevent bugs instead of bypassing it. If I find myself using any or frequent type assertions, I usually rethink the type design first.

 

 

 

 

第三部分:TypeScript 高级类型(Senior 必考,中英双语)

这一部分几乎是 Senior Frontend(React / Next.js) 面试的分水岭。

面试官通常不会问你定义,而是会问:

为什么要这样设计类型?它解决了什么问题?

因此,下面的答案都是偏项目实战的回答方式。

 

Q16. What is keyof and when do you use it?

中文:

什么是 keyof?什么时候会使用它?

English Answer

keyof creates a union of all property names from an object type.

Instead of manually listing property names, we can derive them directly from the type, which keeps the code synchronized as the object evolves.

In React and Next.js projects, I often use keyof for reusable table components, sorting fields, form validation, and generic utility functions.

中文答案

keyof 可以获取一个对象类型的所有属性名,并组成联合类型。

它最大的作用是避免手动维护字段名称,当对象结构发生变化时,类型会自动同步更新。

在实际项目中,我经常把它用于:

面试加分回答

keyof helps eliminate hard-coded property names and makes generic utilities much safer and easier to maintain.

 

Q17. What is typeof in TypeScript?

中文:

TypeScript 中的 typeof 是什么?

English Answer

Unlike JavaScript's runtime typeof, TypeScript's typeof extracts the type of an existing variable or function.

This allows us to reuse inferred types instead of redefining them manually.

It's especially useful when working with configuration objects, constants, or shared APIs.

中文答案

TypeScript 的 typeof 用来获取变量或函数的类型。

它不是运行时操作,而是在编译阶段提取类型。

这样可以避免重复定义类型,提高代码一致性。

面试加分回答

I often use typeof to derive types from configuration objects so that the implementation and the type definition always stay in sync.

 

Q18. What is an Indexed Access Type?

中文:

什么是索引访问类型(Indexed Access Type)?

English Answer

Indexed access types allow us to extract the type of a specific property from another type.

Instead of duplicating a property's type, we reference it directly from the source type.

This keeps related types consistent and reduces maintenance costs.

中文答案

索引访问类型可以获取某个属性对应的类型。

例如,可以直接获取对象中某个字段的类型,而不需要重新定义。

这样可以保证多个类型始终保持一致。

面试加分回答

Indexed access types reduce duplicated type definitions and are commonly used when building reusable business models.

 

Q19. What are Mapped Types?

中文:

什么是 Mapped Type?

English Answer

Mapped types generate new object types by transforming each property of an existing type.

They are commonly used to make properties optional, readonly, or apply consistent transformations across an object.

Many built-in utility types, such as Partial, Required, and Readonly, are implemented using mapped types.

中文答案

Mapped Type 可以遍历一个对象的所有属性,并生成新的类型。

它通常用于:

很多官方工具类型都是基于它实现的。

面试加分回答

Mapped types allow us to transform entire object types consistently instead of manually rewriting every property.

 

Q20. What are Conditional Types?

中文:

什么是条件类型(Conditional Types)?

English Answer

Conditional types allow TypeScript to choose different types based on a condition.

They enable more intelligent and reusable type definitions by expressing logic directly in the type system.

Many advanced utility types rely on conditional types internally.

中文答案

条件类型可以根据条件返回不同的类型。

它让类型系统具有了一定的逻辑判断能力,因此能够构建更加灵活的泛型工具。

很多高级工具类型都是建立在条件类型之上的。

面试加分回答

Conditional types make generic utilities much more expressive because they allow types to adapt automatically based on their inputs.

 

Q21. What is infer?

中文:

什么是 infer?什么时候使用?

English Answer

infer is used inside conditional types to capture and infer a type automatically.

Instead of manually specifying a type, TypeScript extracts it from another type.

This is commonly used to infer function return types, Promise values, or component props.

中文答案

infer 用于条件类型内部,可以自动推导某个类型。

它最大的作用就是让 TypeScript 帮我们提取已有类型中的一部分,而不需要手动声明。

常见场景包括:

面试加分回答

infer enables type extraction without duplication, making utility types much more reusable and maintainable.

 

Q22. What are Utility Types?

中文:

TypeScript 常见的 Utility Types 有哪些?

English Answer

Utility types are built-in generic helpers that simplify common type transformations.

Some of the most frequently used ones include:

Using utility types helps reduce duplicated code and keeps type definitions concise.

中文答案

Utility Types 是 TypeScript 提供的一组官方工具类型。

实际项目中最常用的有:

它们能够减少重复代码,提高类型复用性。

面试加分回答

I prefer using utility types instead of redefining similar interfaces because they keep the type system consistent and much easier to evolve.

 

Q23. What is the difference between Pick and Omit?

中文:

PickOmit 有什么区别?

English Answer

Both are utility types used to derive new object types.

Pick selects only the specified properties.

Omit removes the specified properties and keeps the rest.

I frequently use them when creating API request and response models without duplicating type definitions.

中文答案

两者都是从已有类型生成新类型。

区别在于:

在项目中,经常用于生成不同场景下的数据模型,例如创建请求参数或响应对象。

面试加分回答

Using Pick and Omit keeps related models synchronized and avoids maintaining multiple nearly identical interfaces.

 

Q24. Why is Record useful?

中文:

为什么 Record 很有用?

English Answer

Record creates an object type with a predefined set of keys and a consistent value type.

It's commonly used for dictionaries, configuration maps, localization resources, and lookup tables.

Compared with using a generic object type, Record provides much stronger compile-time guarantees.

中文答案

Record 可以快速创建一个键和值都有明确类型的对象。

常用于:

相比普通对象,它具有更严格的类型检查。

面试加分回答

Record makes configuration objects much safer because every required key must exist and every value follows the same type.

 

Q25. How do you design reusable types in large projects?

中文:

大型项目中,你如何设计可复用的 TypeScript 类型?

English Answer

I avoid defining the same shape multiple times.

Instead, I create shared domain models and derive specialized types using utility types such as Pick, Omit, Partial, and mapped types.

For API contracts, I keep request and response types centralized so that both frontend and backend stay synchronized.

This approach reduces duplication, improves maintainability, and makes refactoring much safer.

中文答案

在大型项目中,我尽量避免重复定义相同的数据结构。

通常会先定义领域模型(Domain Model),然后通过 PickOmitPartial 等工具类型派生不同场景下的类型。

对于 API,我会集中维护请求和响应类型,确保前后端的数据契约保持一致。

这种设计方式可以减少重复代码,提高可维护性,也让后续重构更加安全。

面试加分回答

My goal is to make types reusable rather than repeatedly writing similar interfaces. Well-designed types become part of the project's architecture, not just compiler annotations.

 

 

 

 

 

 

 

第四部分:Next.js + TypeScript 高频面试题(Senior 必考,中英双语)

这一部分的问题几乎都是 React + Next.js 高级岗位 的真实面试题,重点考察你如何将 TypeScript 应用于 App Router、Server Components、Server Actions、Route Handlers 等实际开发场景,而不仅仅是掌握语法。

 

Q26. How do you share types between the frontend and backend in a Next.js project?

中文:

在 Next.js 项目中,你如何实现前后端共享 TypeScript 类型?

English Answer

Since Next.js allows both frontend and backend code to live in the same project, I usually place shared domain models in a common directory, such as types or lib/types.

Both React components and Route Handlers can import these shared types directly, ensuring a single source of truth.

This approach keeps API contracts consistent, reduces duplication, and makes refactoring much safer.

中文答案

由于 Next.js 的前后端代码通常在同一个项目中,我会把公共的数据模型放在 typeslib/types 等共享目录。

前端组件和 Route Handler 都直接引用这些类型,而不是各自重新定义。

这样可以:

面试加分回答

I prefer defining shared domain models once and reusing them across the entire application instead of maintaining separate frontend and backend interfaces.

 

Q27. How do you type API responses?

中文:

API 返回值应该如何定义类型?

English Answer

I define explicit response models instead of relying on inferred or loosely typed objects.

Each API should have a clear response contract so that consumers know exactly what fields are available.

This improves autocomplete, compile-time validation, and reduces runtime errors.

中文答案

我会为每个 API 定义明确的响应类型,而不是依赖 TypeScript 自动推导。

每个接口都应该有清晰的数据契约,让调用方能够准确知道返回的数据结构。

这样可以提高类型安全,也方便后续维护。

面试加分回答

A well-defined response type becomes the API contract, making communication between frontend and backend much more reliable.

 

Q28. Why shouldn't you use any for API data?

中文:

为什么 API 返回值不应该使用 any

English Answer

Using any removes all compile-time validation, which means TypeScript can no longer detect incorrect property access or missing fields.

API data comes from external sources, so it should always be treated as potentially unsafe until properly validated.

Strong typing helps catch integration issues early during development.

中文答案

API 数据来自外部系统,本身是不可信的。

如果使用 any,TypeScript 就无法检查字段是否存在或类型是否正确。

这会增加运行时错误的风险。

因此应该使用明确的数据类型,并在必要时结合数据校验工具进行验证。

面试加分回答

The purpose of TypeScript is to prevent runtime bugs. Using any for external data defeats that purpose.

 

Q29. Why is Zod commonly used with TypeScript?

中文:

为什么很多 Next.js 项目都会使用 Zod?

English Answer

TypeScript only performs compile-time type checking, while Zod validates data at runtime.

Together, they provide both static type safety and runtime validation.

This is especially important for API requests, form submissions, and user input, where external data cannot be fully trusted.

中文答案

TypeScript 只能在编译阶段检查类型,运行时不会进行验证。

而 Zod 可以在运行时验证数据是否合法。

两者结合后,可以同时保证:

因此在表单、API、Server Actions 等场景中非常常见。

面试加分回答

TypeScript verifies our code, while Zod verifies external data. They solve different problems and complement each other well.

 

Q30. What is z.infer?

中文:

什么是 z.infer

English Answer

z.infer generates a TypeScript type directly from a Zod schema.

Instead of defining the schema and the interface separately, we define the schema once and derive the type automatically.

This eliminates duplication and guarantees that validation logic and TypeScript types stay synchronized.

中文答案

z.infer 可以根据 Zod Schema 自动生成 TypeScript 类型。

这样无需再额外编写 interface 或 type。

Schema 和类型始终保持一致,避免维护两份定义。

面试加分回答

I prefer schema-first development because validation rules and TypeScript types are always derived from the same source.

 

Q31. How do you type Server Actions?

中文:

Server Action 应该如何定义类型?

English Answer

Server Actions are simply asynchronous server-side functions.

Their parameters and return values should be explicitly typed, just like any other public API.

This provides better autocomplete and prevents accidental misuse by client components.

中文答案

Server Action 本质上就是运行在服务器端的异步函数。

因此应该明确声明:

这样可以保证调用方获得完整的类型提示,也便于后续维护。

面试加分回答

I treat Server Actions as part of the backend API layer, so I always define clear input and output types.

 

Q32. How do you type Route Handlers?

中文:

Route Handler 应该如何定义类型?

English Answer

Each Route Handler should define the expected request data and the response model.

Instead of returning loosely typed objects, I ensure the response follows a consistent contract so that frontend consumers always know what to expect.

中文答案

Route Handler 应该明确:

这样前端能够清楚知道接口返回的数据结构,也方便接口演进。

面试加分回答

Consistent request and response models make APIs easier to maintain and significantly reduce frontend-backend integration issues.

 

Q33. How do you type React Query?

中文:

React Query 应该如何结合 TypeScript?

English Answer

I always define the data model returned by the query function.

Once the query function is properly typed, React Query can infer the types for data, loading states, and callbacks automatically.

This provides strong type safety without requiring repetitive annotations.

中文答案

我会优先定义查询函数的返回类型。

React Query 会根据查询函数自动推导:

这样既减少重复声明,又能获得完整的类型提示。

面试加分回答

Instead of manually typing every query result, I rely on inference from the query function to keep the code concise and maintainable.

 

Q34. How do you keep API contracts consistent?

中文:

如何保证 API Contract 的一致性?

English Answer

I define shared request and response models that are reused across the application.

Whenever the API changes, both frontend and backend compile against the same types, allowing TypeScript to catch inconsistencies immediately.

This greatly reduces integration bugs.

中文答案

我会维护统一的请求和响应类型。

前后端共同使用这些类型,而不是分别维护。

这样一旦接口发生变化,TypeScript 会立即提示所有受影响的位置,从而避免线上问题。

面试加分回答

A shared API contract turns many runtime integration errors into compile-time errors, making deployments much safer.

 

Q35. How do you organize TypeScript types in a large Next.js project?

中文:

大型 Next.js 项目中,你如何组织 TypeScript 类型?

English Answer

I organize types based on business domains rather than creating one large global types file.

Each feature owns its local types, while shared domain models and utility types are placed in dedicated shared directories.

This structure keeps dependencies clear and prevents the type system from becoming difficult to navigate.

中文答案

我更倾向于按照业务模块组织类型,而不是把所有类型都放到一个文件中。

通常会分为:

这样随着项目增长,类型系统仍然保持清晰和易维护。

面试加分回答

I organize types around business domains because it scales much better than maintaining a single global types folder as the application grows.

 

 

 

 

很好,我们继续进入第五部分:TypeScript 架构设计(Staff / Senior+)

这一部分和前面的最大区别是:

前面考的是:"你会不会 TypeScript?"

这一部分考的是:"你能不能设计一套类型系统?"

这些问题我见过在 TikTok、字节、Shopee、Grab、Airwallex、Stripe、Microsoft、Amazon 等公司的 Senior Frontend 面试中出现过。

 

Q36. How do you design a reusable API response type?

中文:

如何设计一个可复用的 API Response 类型?

English Answer

Instead of defining a different response type for every API, I prefer creating a generic response model.

Most APIs share common fields such as the response data, status code, message, or pagination metadata. A generic type allows us to reuse the same structure while keeping the payload type flexible.

This approach improves consistency across the project and reduces duplicated type definitions.

中文答案

我不会为每个接口都单独定义一个 Response 类型,而是设计一个通用的响应模型。

大部分接口都有一些公共字段,例如:

通过泛型,可以让 data 保持灵活,同时复用统一的响应结构。

这样既减少重复代码,又能保证整个项目接口风格一致。

面试加分回答

I try to model common API patterns once and reuse them through generics, rather than redefining nearly identical response types for every endpoint.

 

Q37. How do you design a reusable DataTable component?

中文:

如何设计一个支持任何数据类型的 DataTable?

English Answer

I make the component generic so it doesn't depend on a specific data model.

The table should infer the row type from the data it receives. Columns, cell renderers, sorting logic, and callbacks should all derive their types from that generic parameter.

This keeps the component reusable while providing full type safety and autocomplete.

中文答案

我会把 DataTable 设计成泛型组件,而不是绑定某一种数据结构。

数据类型由调用方决定,列配置、单元格渲染、排序和事件回调都基于同一个泛型推导。

这样一个组件就可以服务多个业务模块,同时保持完整的类型安全。

面试加分回答

A generic table should know nothing about the business model. It only understands the shape of the data through its type parameter.

 

Q38. What makes a good TypeScript API?

中文:

什么样的 TypeScript API 才算设计得好?

English Answer

A good TypeScript API should be easy to understand, easy to use, and difficult to misuse.

It should rely on type inference whenever possible, minimize the need for manual annotations, and expose clear error messages when developers use it incorrectly.

The best API feels natural because developers rarely need to think about its types.

中文答案

好的 TypeScript API 应该具备几个特点:

同时应该充分利用类型推导,减少调用方手动写类型的负担。

如果使用方式错误,类型系统应该尽早给出明确的提示。

面试加分回答

The best TypeScript APIs guide developers toward the correct usage instead of relying on documentation alone.

 

Q39. What are common mistakes when designing generic types?

中文:

设计泛型时有哪些常见错误?

English Answer

One common mistake is introducing generics when they aren't actually needed.

Another is using too many type parameters, which makes the API difficult to understand.

Overly complex conditional types can also slow down TypeScript compilation and make error messages much harder to interpret.

I prefer keeping generic APIs simple and introducing complexity only when it provides clear value.

中文答案

常见错误包括:

我的原则是:先保持简单,再逐步扩展。

面试加分回答

Generics should improve developer experience, not make the API harder to understand.

 

Q40. How do you balance type safety and developer experience?

中文:

如何平衡类型安全和开发体验?

English Answer

Type safety is important, but it shouldn't make the API difficult to use.

I rely on type inference as much as possible and only require explicit type annotations when they improve clarity.

The goal is to provide strong compile-time guarantees while keeping the developer experience smooth and intuitive.

中文答案

类型安全固然重要,但不能为了类型而牺牲开发效率。

我会尽量利用 TypeScript 的自动推导能力,只有在必要时才要求开发者显式声明类型。

目标是在保证安全性的同时,让 API 使用起来足够自然。

面试加分回答

Good type design should make the correct usage the easiest usage.

 

Q41. How do you prevent duplicated type definitions?

中文:

如何避免项目中出现大量重复的类型定义?

English Answer

I start with shared domain models and derive specialized types using utility types such as Pick, Omit, and Partial.

Instead of creating separate interfaces for every use case, I build new types from existing ones.

This reduces duplication and keeps related models synchronized.

中文答案

我会先定义领域模型(Domain Model)。

然后利用:

派生出不同业务场景需要的类型。

这样避免维护多份几乎相同的接口定义。

面试加分回答

Whenever I notice similar interfaces appearing repeatedly, I consider extracting a shared model instead.

 

Q42. What is your philosophy for using TypeScript?

中文:

你的 TypeScript 使用理念是什么?

English Answer

I see TypeScript as a design tool rather than just a type checker.

Good types document the system, prevent incorrect usage, and make large codebases easier to evolve.

My goal isn't to maximize the number of advanced types, but to create APIs that are safe, maintainable, and easy for other developers to understand.

中文答案

我认为 TypeScript 不只是一个类型检查工具,更是一种设计工具。

好的类型应该能够:

我的目标不是追求复杂的高级类型,而是设计出简单、清晰、可靠的类型系统。

面试加分回答

I use TypeScript to communicate intent. Well-designed types make the codebase easier to understand long before anyone reads the implementation.

 

 

 

 

 

 

第六部分:TypeScript 高级手写题(Senior Frontend 高频 Coding Interview)

这一部分是很多大厂 Senior Frontend 面试最后一轮会考察的内容。

重点不是让你背 Utility Types,而是看你是否理解:

 

Q43. Implement MyPick<T, K>

中文:

手写 TypeScript 内置工具类型 Pick<T, K>

Interview Question

English:

Can you implement your own version of TypeScript's Pick utility type?

中文:

你能实现一个自己的 Pick 类型吗?

Expected Answer

Explanation

English

Pick creates a new type by selecting specific properties from an existing type.

The important parts are:

中文

Pick 的作用是:

从已有对象类型中选择部分字段生成新的类型。

关键点:

限制 K 必须是 T 存在的 key。

例如:

结果:

 

Q44. Implement MyOmit<T, K>

中文:

手写 Omit<T, K>

Expected Answer

Explanation

English

Omit removes specified properties from a type.

The implementation works by:

  1. Getting all keys:
  1. Removing unwanted keys:
  1. Picking the remaining keys.

中文

Omit 的逻辑:

例如:

得到:

步骤:

第一步:

获取所有 key:

第二步:

删除:

第三步:

重新 Pick。

 

Q45. Implement MyReadonly<T>

中文:

实现 Readonly<T>

Expected Answer

Explanation

English

Mapped types allow us to transform every property.

Here we iterate over all keys and add the readonly modifier.

中文

Mapped Type 可以遍历对象所有属性。

这里:

遍历所有字段。

然后:

增加只读限制。

 

Q46. Implement MyPartial<T>

中文:

实现 Partial<T>

Expected Answer

Explanation

English

Partial converts all required properties into optional properties.

中文

例如:

原始:

Partial:

 

Q47. Implement MyReturnType<T>

中文:

实现 ReturnType<T>

Expected Answer

Explanation

这是高级面试非常喜欢问的一题。

核心:

English

The conditional type checks whether T is a function.

If it is, infer R captures the return type.

Otherwise, it returns never.

中文

这里:

表示:

如果 T 是函数类型:

提取它的返回值类型。

例如:

得到:

 

Q48. Implement MyParameters<T>

中文:

实现 Parameters<T>

Expected Answer

Explanation

English

Instead of extracting the return type, we extract the function arguments.

中文

例如:

结果:

 

Q49. Implement DeepPartial<T>

中文:

实现深度 Partial。

Interview Question

Make every nested property optional.

Expected Answer

Example

原始:

DeepPartial:

面试重点

面试官关注:

你是否理解:

 

Q50. Implement Flatten<T>

中文:

实现数组扁平化类型。

Expected Answer

Example

结果:

 

Q51. How would you design a type-safe EventEmitter?

中文:

如何设计一个类型安全的 EventEmitter?

Interview Answer

English

Instead of allowing arbitrary strings as event names, I define an event map where each event has its own payload type.

The emitter methods use generic constraints to ensure that the event name and payload always match.

中文

传统 EventEmitter:

问题:

任何事件都可以传任何数据。

更好的设计:

定义 Event Map:

然后:

这样:

正确。

但是:

会报错。

 

Q52. How do you type a generic React DataTable?

中文:

如何设计一个类型安全的 DataTable?

Interview Answer

Usage

中文解释

核心思想:

DataTable 不知道业务数据是什么。

它只知道:

"我接受一个 T 类型的数据,然后所有配置都基于 T 推导。"

这就是大型组件库的设计方式。

 

 

 

 

 

 

第七部分:React + Next.js TypeScript 实战架构题(Senior / Staff 面试)

这一部分是实际工作中最常遇到的问题。

面试官通常不会再问:

"什么是 interface?"

而会问:

"如果你负责一个大型 Next.js 项目,你如何设计 TypeScript 架构?"

 

Q53. How would you design a type-safe useFetch<T>() hook?

中文:

如何设计一个类型安全的 useFetch<T>() Hook?

Interview Question

English:

How would you create a reusable fetch hook that provides type safety for different API responses?

中文:

如何设计一个通用请求 Hook,同时保证不同 API 返回不同类型的数据?

Good Answer

English Answer

I would make the hook generic so that the caller can specify or infer the response type.

The hook should not know business details. It only handles request states such as:

The API layer defines the actual response models.

中文答案

我会使用泛型设计:

让调用方决定返回的数据类型。

Hook 本身只负责:

业务数据类型由 API 层提供。

Example

Usage

TypeScript 自动知道:

是:

面试加分回答

A generic hook keeps the fetching logic reusable while allowing each feature module to maintain its own domain types.

 

 

Q54. How do you type React Query properly?

中文:

React Query 如何进行类型设计?

English Answer

I avoid manually typing the returned data everywhere.

Instead, I make sure the query function has a correct return type.

React Query can infer the type automatically from the query function.

中文答案

我不会在每个组件里面重复声明:

而是保证:

queryFn 本身类型正确。

React Query 会自动推导。

Example

API:

Query:

自动推导:

面试加分回答

I prefer inference from the source function because it keeps types centralized and avoids duplicated annotations.

 

 

Q55. How do you design API types with Prisma in Next.js?

中文:

Next.js + Prisma 项目中,数据库类型应该如何设计?

English Answer

I avoid exposing Prisma models directly to the frontend.

Database models represent storage, while API models represent business contracts.

I usually create DTO types and transform Prisma results before returning them.

中文答案

不要直接把 Prisma Model 暴露给前端。

原因:

数据库结构 ≠ 前端业务模型。

例如:

数据库:

但是:

前端:

所以应该:

Database Model

DTO

Frontend Type

Example

Prisma:

转换:

返回:

面试加分回答

Separating database models and API DTOs gives us flexibility to change storage without breaking frontend contracts.

 

 

Q56. How do you type Server Actions in Next.js?

中文:

Next.js Server Action 如何设计类型?

English Answer

I treat Server Actions like backend functions.

They should have:

For complex data, I usually combine TypeScript with Zod.

中文答案

我把 Server Action 看作后端 API。

应该包含:

  1. 输入类型
  2. 参数验证
  3. 返回类型

复杂场景:

TypeScript + Zod。

Example

Schema:

Type:

Action:

面试加分回答

TypeScript provides developer safety, while Zod protects the application at runtime.

 

 

Q57. How do you design shared DTOs between frontend and backend?

中文:

如何设计前后端共享 DTO?

English Answer

I create a dedicated domain layer containing shared contracts.

For example:

The frontend and backend both depend on these contracts.

中文答案

我会建立独立的 Contract Layer:

例如:

里面只保存:

面试加分回答

The contract layer becomes the communication boundary between frontend and backend.

 

 

Q58. How do you build a type-safe form in React?

中文:

如何设计类型安全的 React Form?

English Answer

I usually combine:

The schema defines validation rules and automatically generates the TypeScript type.

This prevents the form type and validation rules from becoming inconsistent.

中文答案

常见方案:

Example:

Form:

这样:

全部类型安全。

面试加分回答

Schema-first form design reduces duplication because validation rules and TypeScript types share the same source.

 

 

Q59. How do you prevent TypeScript type explosion in large projects?

中文:

大型项目如何避免 TypeScript 类型爆炸?

English Answer

Type complexity can become a real problem in large applications.

I avoid:

Instead, I prefer simple domain models and clear boundaries between modules.

中文答案

大型项目中 TypeScript 也可能成为性能问题。

避免:

1. 过度使用 Conditional Types

例如:

嵌套太深。

2. 泛型参数过多

不要:

除非真的需要。

3. 类型职责混乱

不要:

一个 type 文件包含:

面试加分回答

Type systems should model business complexity, not create additional complexity.

 

 

Q60. How do you optimize TypeScript performance?

中文:

如何优化 TypeScript 编译性能?

English Answer

For large projects, TypeScript performance can become an issue.

Common optimizations include:

中文答案

大型项目中 TypeScript 编译速度可能下降。

常见优化:

1. Project References

拆分 tsconfig:

2. 避免复杂类型

例如:

3. 使用:

减少第三方库检查。

4. 清晰模块边界

减少 TypeScript 需要分析的范围。