全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页

TypeScript 高级技能认证测试

20 题 90 分钟 难度:

考察知识点

  • 高阶类型体系: 类型兼容性、类型守卫进阶、条件类型深入、类型系统原理、高级类型模式
  • 高阶工具类型: 条件类型(infer/分布式)、模板字面类型、映射类型进阶、元组类型操作、自定义工具类型
  • 深度类型编程: 类型级计算、递归类型、类型约束高级技巧、类型系统设计、类型编程模式
  • 高阶文件声明: 复杂声明语法、模块增强、第三方库声明、声明文件优化、声明发布
1
多选题

关于 keyof 操作符在 TypeScript 中的行为,以下哪些说法是正确的?

A. keyof string[] 的结果包含 number 类型,因为数组索引是数字 B. keyof readonly number[] 的结果与 keyof number[] 完全相同 C. 当一个类包含 private 字段时,keyof 该类的结果仍然只包含 public 成员的键 D. keyof typeof someObject 可以获取对象值的类型,而不仅仅是键的联合类型

2
简答题

以下代码存在类型错误,请分析错误原因并提供修复方案:

TypeScript
const routes = {
  getUsers: '/api/users',
  getUserById: '/api/users/:id',
  createUser: '/api/users'
};

// 目标:创建一个类型安全的 getRoute 函数
// 只接受 routes 对象中存在的键,并返回对应的路径字符串
function getRoute(routeName: keyof routes): string {
  return routes[routeName];
}

// 期望的调用:
// getRoute('getUsers')      // 正确
// getRoute('getProducts')   // 应报类型错误

请指出代码中的错误,并给出正确的实现。

3
填空题
TypeScript
interface EventMap {
  click: { x: number; y: number };
  keydown: { key: string; code: number };
  resize: { width: number; height: number };
}

function handleEvent<K extends keyof EventMap>(
  eventName: K,
  handler: (event: !!1_答案!!) => void
): void {
  // ...
}

请填写正确的类型表达式,使得 handler 的参数类型能够根据 eventName 的类型自动推导为对应的事件数据类型。例如,当 eventName"click" 时,event 参数应为 { x: number; y: number } 类型。

4
多选题

考虑以下代码:

TypeScript
type Shape = Circle | Rectangle | Triangle;

interface Circle { kind: 'circle'; radius: number }
interface Rectangle { kind: 'rectangle'; width: number; height: number }
interface Triangle { kind: 'triangle'; base: number; height: number }

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case 'circle': return Math.PI * shape.radius ** 2;
    case 'rectangle': return shape.width * shape.height;
    case 'triangle': return 0.5 * shape.base * shape.height;
    default:
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

关于上述代码,以下哪些说法是正确的?

A. 如果向 Shape 联合类型中添加 Square 类型但不添加对应的 case 分支,TypeScript 会在 default 行报类型错误 B. _exhaustive: never = shape 利用了 TypeScript 的穷举检查模式,确保所有联合类型分支都被处理 C. 将 default 分支改为 throw new Error() 后,_exhaustive 行可以省略,因为 TypeScript 知道该分支不会返回 D. 如果删除 default 分支,函数仍然能正确处理所有 Shape 类型,因为 TypeScript 的控制流分析会自动推导

5
多选题

关于 TypeScript 条件类型 T extends U ? X : Y,以下哪些说法是正确的?

A. 条件类型中的 extends 与泛型约束中的 extends 含义相同,都表示子类型关系判断 B. T extends U ? X : Y 中的 XY 可以是类型推导表达式,包含对 TU 的引用 C. 当 T 是联合类型时,条件类型会自动对联合类型的每个成员分别应用条件判断,这称为分布式条件类型 D. 嵌套条件类型如 A extends B ? C extends D ? E : F : G 的解析顺序是从左到右,等价于 (A extends B ? (C extends D ? E : F) : G)

6
简答题

TypeScript 内置的 Exclude<T, U>Extract<T, U> 工具类型的定义如下:

TypeScript
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;

请分析:

  1. T = 'a' | 'b' | 'c'U = 'a' | 'b' 时,Exclude<T, U>Extract<T, U> 分别得到什么结果?推导过程是什么?
  2. 为什么这两个类型定义中使用了 never,但最终结果中不会出现 never
  3. 如果将定义改为非分布式写法 [T] extends [U] ? never : T,结果会有什么不同?
7
多选题

在 TypeScript 中,以下哪个(些)工具类型定义能够正确实现一个 DeepRequired<T>,使其递归地将对象类型 T 及其所有嵌套属性的可选修饰符移除(即所有属性变为 required)?

A

type DeepRequired<T> = T extends object ? { [K in keyof T]-?: DeepRequired<T[K]> } : T

B

type DeepRequired<T> = { [K in keyof T]-?: T[K] extends object ? DeepRequired<T[K]> : T[K] }

C

type DeepRequired<T> = T extends object ? { [K in keyof T]-?: NonNullable<T[K]> extends object ? DeepRequired<NonNullable<T[K]>> : NonNullable<T[K]> } : T

D

type DeepRequired<T> = Required<T> extends infer R ? R extends object ? { [K in keyof R]: DeepRequired<R[K]> } : R : never

8
填空题

请补全以下工具类型 RenameField<T, OldKey, NewKey>,使其能够将对象类型 T 中的指定属性 OldKey 重命名为 NewKey,同时保持其他属性和类型不变。

TypeScript
type RenameField<T, OldKey extends keyof T, NewKey extends string> = 
  Omit<T, OldKey> & !!1_Record<NewKey, T[OldKey]>!!

当使用 RenameField<{ name: string; age: number }, "name", "userName"> 时,结果类型应等价于 { age: number; userName: string }

请写出 !!1!! 处应填入的类型工具名称。

9
多选题

在自定义复杂工具类型时,关于联合类型的分发行为,以下哪些说法是正确的?

A

条件类型T extends U ? X : Y中,当T是联合类型时会自动分发为多个独立判断

B

使用[T] extends [U]可以阻止条件类型的分发行为

C

所有工具类型都应该使用分发行为以获得更好的类型推导

D

NonNullable<T>是分发条件类型的典型应用

10
填空题
TypeScript
// 实现 DeepPartial<T>:递归地将对象 T 的所有属性变为可选
// 包括嵌套对象和数组中的对象也需要处理

type DeepPartial<T> = T extends object
  ? { [K in keyof T]?: !!1_答案!! }
  : T;

// 测试
interface Nested {
  a: {
    b: { c: string };
  };
  items: { name: string }[];
}

type Result = DeepPartial<Nested>;
// 期望: {
//   a?: { b?: { c?: string } };
//   items?: { name?: string }[];
// }
11
多选题

关于 TypeScript 中递归类型的特性,以下哪些说法是正确的?

A

在 TypeScript 4.1 之前,interface 可以隐式支持递归,而 type 别名不支持直接递归

B

递归类型可以用来定义树形结构,如二叉树 type Tree = { value: number; left?: Tree; right?: Tree }

C

递归类型的深度在运行时受到 JavaScript 调用栈的限制,但在编译时类型检查没有深度限制

D

使用递归类型时,TypeScript 编译器会在类型展开过程中进行"递归深度"检测以防止无限循环

12
填空题

以下类型用于将嵌套数组展平为一维数组,请填写 ______ 处缺失的代码:

TypeScript
type Flatten<T> = T extends (infer U)[]
  ? !!1_答案!!
  : T;

// 测试:
// type Result = Flatten<number[][][]>  // 应为 number
// type Result2 = Flatten<string>       // 应为 string
13
多选题

以下关于递归类型别名的使用限制和技巧,哪些说法是正确的?

A

递归类型别名必须至少有一个非递归的"基础情况"(base case),否则会导致类型无限展开

B

type Loop = Loop 是合法的递归类型别名定义,但类型 Loop 永远无法被实例化

C

递归类型别名可以与条件类型结合使用,实现类型级别的递归计算,如计算元组长度

D

TypeScript 对递归类型别名的展开有硬性深度限制,可以通过编译器配置调整此限制

14
多选题

关于 TypeScript 中泛型的协变(covariance)与逆变(contravariance),以下哪些说法是正确的?

A

对于函数类型 (x: Animal) => void(x: Dog) => void(其中 Dog extends Animal),前者是后者的子类型,这体现了参数位置的逆变性

B

TypeScript 数组类型 Array<T> 是协变的,即 Array<Dog>Array<Animal> 的子类型

C

TypeScript 严格模式下,函数参数的类型检查使用逆变规则,而函数返回值使用协变规则

D

一个泛型接口 Wrapper<T> 如果既在协变位置又在逆变位置使用 T,则 T 在该接口中是不变的(invariant)

15
多选题

关于 TypeScript 编译器(tsc)的编译流程,以下说法正确的有哪些?

A

TypeScript 编译器首先进行词法分析(Lexical Analysis),将源代码转换为 Token 流

B

语法分析(Parsing)阶段会生成抽象语法树(AST),TypeScript 使用的是自己定制的 AST 格式,与 ESTree 不完全兼容

C

类型检查(Type Checking)是在 AST 生成之后、代码发射(Emit)之前独立执行的阶段

D

代码发射(Emit/Transpilation)阶段会将 TypeScript 特有的语法(如 interface、enum)转换为等价的 JavaScript 代码

16
填空题

在 TypeScript 的结构化类型系统中,判断以下函数类型的赋值兼容性:

TypeScript
type Handler = (x: string | number) => void;
type SpecificHandler = (x: string) => void;

const h1: Handler = function(x: string) { console.log(x); };
const h2: SpecificHandler = function(x: string | number) { console.log(x); };

上述代码中,赋值语句 const h1: Handler = ... 是否会报类型错误?赋值语句 const h2: SpecificHandler = ... 是否会报类型错误?

请分别回答:h1 赋值 ________,h2 赋值 ______。(填写"会报错"或"不会报错")

17
多选题

TypeScript 编译器在词法分析阶段会生成哪些产物?

A

Token 流(词法单元序列)

B

抽象语法树(AST)

C

符号表(Symbol Table)的初步信息

D

类型检查报告

18
填空题

在 TypeScript 的结构化类型系统中,函数 A = (x: Animal) => void 能否赋值给函数 B = (x: Dog) => void

答案:________________________

19
简答题

TypeScript 内置的 Pick<T, K>Omit<T, K> 工具类型定义如下:

TypeScript
type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

请分析:

  1. Pick 类型中的 K extends keyof T 约束的作用是什么?如果去掉这个约束会有什么问题?
  2. Omit 如何通过组合 PickExclude 实现"排除指定键"的功能?
  3. 如果直接使用映射类型写 Omit,如下所示,与原定义有什么区别?
    TypeScript
    type OmitDirect<T, K extends keyof T> = {
      [P in keyof T as P extends K ? never : P]: T[P];
    };
    
20
简答题

请解释为什么函数参数位置是逆变的,而返回值位置是协变的。请通过具体的代码示例说明,如果不遵守这些规则会导致什么样的类型安全问题。

← 上一个试卷 TypeScript 初级技能认证测试
下一个试卷 → 声明文件基础专题测试

📝 发现内容有误?点击此处直接编辑

想参加完整模拟考试?
小程序提供计时考试、自动评分和详细解析

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库