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

深度类型编程专题测试

12 题 90 分钟 难度:

考察知识点

  1. 类型级计算: 数字类型运算、字符串操作、布尔逻辑
  2. 递归类型: 递归推断、深度遍历、树形类型处理
  3. 类型约束高级技巧: 复杂约束组合、约束传递、约束推导
  4. 类型系统设计: 类型抽象、类型多态、类型继承
  5. 类型编程模式: 类型工厂、类型组合子、类型元编程
1
多选题

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

A

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

B

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

C

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

D

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

2
多选题

以下哪些类型定义是正确的递归类型定义?

A

type LinkedList<T> = { value: T; next?: LinkedList<T> }

B

type NestedArray<T> = T | NestedArray<T>[]

C

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

D

type JsonValue = string | number | boolean | null | JsonObject | JsonArray; type JsonObject = { [key: string]: JsonValue }; type JsonArray = JsonValue[]

3
填空题

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

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

// 测试:
// type Result = Flatten<number[][][]>  // 应为 number
// type Result2 = Flatten<string>       // 应为 string
4
简答题

请实现一个递归类型 DeepReadonly<T>,将对象的所有层级(包括嵌套对象和数组)都变为 readonly。请解释你的实现思路,并说明为什么需要递归。

5
多选题

关于 TypeScript 中递归类型别名(recursive type aliases),以下哪些说法是正确的?

A

在 TypeScript 4.1 中引入递归类型别名支持后,type 别名可以直接引用自身

B

type Json = string | number | boolean | null | { [key: string]: Json } | Json[] 在 TypeScript 4.1+ 中是合法的类型定义

C

递归类型别名在 TypeScript 中的展开深度限制与递归 interface 完全相同

D

递归类型别名可以用于定义 JSON Schema 的类型约束,因为它能精确描述 JSON 数据的所有可能形态

6
多选题

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

A

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

B

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

C

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

D

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

7
填空题

以下类型用于提取对象中所有叶子节点值的联合类型,请填写 ______ 处缺失的代码:

TypeScript
type LeafValue<T> = T extends object
  ? !!1_答案!!
  : T;

// 测试:
// type Data = { a: { b: number }; c: string };
// type Result = LeafValue<Data>  // 应为 number | string
8
简答题

请比较递归类型别名(type)与递归接口(interface)在定义树形结构时的区别。请以二叉树为例,分别用两种方式定义,并分析它们在类型检查行为、可扩展性和使用场景上的差异。

9
多选题

关于 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)

10
多选题

以下哪些场景涉及函数类型变型规则的实际应用?

A

(e: MouseEvent) => void 赋值给期望 (e: Event) => void 的参数时,利用了参数位置的逆变性

B

定义 Promise<T> 时,T 只出现在 then 回调的返回值位置,因此 Promise<Dog>Promise<Animal> 的子类型

C

事件监听器 addEventListener('click', handler) 中,handler 可以接受比 MouseEvent 更窄的类型

D

Record<K, V> 中,K 出现在键位置(逆变),V 出现在值位置(协变),因此 Record<string, Dog>Record<string, Animal> 的子类型

11
填空题

已知 class Animal {}class Dog extends Animal {}class Cat extends Animal {}。请判断以下赋值是否合法,在 ______ 处填写 合法不合法

TypeScript
type Handler<T> = (value: T) => T;

declare let handlerAnimal: Handler<Animal>;
declare let handlerDog: Handler<Dog>;

// 赋值 1:handlerDog = handlerAnimal
handlerDog = handlerAnimal;  // ______
12
简答题

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

← 上一个试卷 泛型专题测试
下一个试卷 → 环境搭建与基础配置专题测试

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

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

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

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