0

0

TypeScript 教程:在映射类型中实现可选且受限的对象键

心靈之曲

心靈之曲

发布时间:2025-11-22 15:57:18

|

260人浏览过

|

来源于php中文网

原创

TypeScript 教程:在映射类型中实现可选且受限的对象键

本教程探讨如何在 typescript 中定义一个对象类型,使其键值受限于预定义集合,同时允许这些键是可选的,而非强制。通过利用 typescript 的映射修饰符 `?`,我们能够灵活地构建嵌套对象类型,避免因缺少部分键而导致的类型错误,从而提升类型定义的灵活性和实用性。

在 TypeScript 中定义复杂的数据结构时,我们经常需要创建一种对象类型,其键名必须来自某个预定义的集合,但同时又希望这些键是可选的,即不必全部存在。这在构建配置对象、API 响应或灵活的数据字典时尤为常见。本文将深入探讨如何使用 TypeScript 的映射类型(Mapped Types)及其修饰符来优雅地解决这一问题。

1. 问题背景与初始尝试

假设我们有两组常量,分别定义了两种类型的标识符:

export const ABC = {
  A: 'A',
  B: 'B',
  C: 'C',
} as const;

export const DEF = {
  D: 'D',
  E: 'E',
  F: 'F',
} as const;

// 提取这些常量的值作为联合类型
export type AbcTypes = (typeof ABC)[keyof typeof ABC]; // 'A' | 'B' | 'C'
export type DefTypes = (typeof DEF)[keyof typeof DEF]; // 'D' | 'E' | 'F'

现在,我们的目标是构建一个嵌套对象 MyNewDictionary,其结构如下:

  • 第一层键必须是 AbcTypes 中的值。
  • 第二层键必须是 DefTypes 中的值。
  • 最内层对象包含 onClick 和 onCancel 两个函数。

最初的尝试可能会是这样:

type MyNewDictionary = {
  [pKey in AbcTypes]: {
    [eKey in DefTypes]: {
      onClick: () => void;
      onCancel: () => void;
    }
  }
};

然而,当我们尝试创建一个 MyNewDictionary 类型的实例,但只填充部分键时,TypeScript 会立即报错:

const dictionary: MyNewDictionary = {
  [ABC.A]: {
    [DEF.D]: {
      onClick: () => null,
      onCancel: () => null,
    }
  }
};
// 错误信息示例:
// Type '{ D: { onClick: () => null; onCancel: () => null; }; }' is missing the following properties from type '{ D: { onClick: () => void; onCancel: () => void; }; E: { onClick: () => void; onCancel: () => void; }; F: { onClick: () => void; onCancel: () => void; }; }': 'E', 'F'
// 并且外层也可能报错,因为缺少 'B', 'C'

这个错误表明,当前 MyNewDictionary 的定义强制要求所有 AbcTypes 和 DefTypes 中的键都必须存在。使用 Partial 作用于整个 MyNewDictionary 类型可能无法完全解决嵌套层级的可选性问题,因为它只会使顶层属性可选,而嵌套的映射类型内部仍然是强制的。

FaceSwapper
FaceSwapper

FaceSwapper是一款AI在线换脸工具,可以让用户在照片和视频中无缝交换面孔。

下载

2. 解决方案:映射修饰符 ?

TypeScript 提供了强大的映射修饰符来改变映射类型中属性的特性。其中,? 修饰符用于将属性标记为可选(Optional)。通过在映射类型中直接应用 ?,我们可以精确控制哪些属性是可选的。

将 ? 修饰符应用于上述 MyNewDictionary 的定义,可以使其内部的键变为可选:

type MyNewDictionaryCorrected = {
  [pKey in AbcTypes]?: { // 使第一层键可选
    [eKey in DefTypes]?: { // 使第二层键可选
      onClick: () => void;
      onCancel: () => void;
    }
  }
};

在这个修正后的类型定义中:

  • [pKey in AbcTypes]?:表示 MyNewDictionaryCorrected 的第一层属性,其键名来自 AbcTypes,但这些属性是可选的。
  • [eKey in DefTypes]?:表示内层对象的属性,其键名来自 DefTypes,同样是可选的。

3. 完整示例与验证

现在,使用 MyNewDictionaryCorrected 类型,我们可以创建只包含部分键的对象,而不会遇到类型错误:

export const ABC = {
  A: 'A',
  B: 'B',
  C: 'C',
} as const;

export const DEF = {
  D: 'D',
  E: 'E',
  F: 'F',
} as const;

export type AbcTypes = (typeof ABC)[keyof typeof ABC];
export type DefTypes = (typeof DEF)[keyof typeof DEF];

type MyNewDictionaryCorrected = {
  [pKey in AbcTypes]?: {
    [eKey in DefTypes]?: {
      onClick: () => void;
      onCancel: () => void;
    }
  }
};

// 示例 1:只包含一个顶层键和一个内层键
const dictionary1: MyNewDictionaryCorrected = {
  [ABC.A]: {
    [DEF.D]: {
      onClick: () => console.log('A.D onClick'),
      onCancel: () => console.log('A.D onCancel'),
    }
  }
};
console.log(dictionary1); // 类型检查通过

// 示例 2:包含多个顶层键,但每个顶层键下只包含部分内层键
const dictionary2: MyNewDictionaryCorrected = {
  [ABC.A]: {
    [DEF.D]: { onClick: () => {}, onCancel: () => {} },
    [DEF.F]: { onClick: () => {}, onCancel: () => {} },
  },
  [ABC.C]: {
    [DEF.E]: { onClick: () => {}, onCancel: () => {} },
  }
};
console.log(dictionary2); // 类型检查通过

// 示例 3:尝试使用非定义的键,会报错
// const invalidDictionary: MyNewDictionaryCorrected = {
//   'X': { // 错误:类型 '"X"' 不可分配给类型 'AbcTypes'
//     [DEF.D]: { onClick: () => {}, onCancel: () => {} }
//   }
// };

通过这个例子,我们可以看到 MyNewDictionaryCorrected 成功地实现了我们的需求:键名受限于 AbcTypes 和 DefTypes,但它们都是可选的。

4. 总结与注意事项

  • 映射修饰符的力量:? 是 TypeScript 映射类型中非常有用的修饰符,它允许我们精确地控制属性的可选性。除了 ?,还有 readonly 修饰符(以及它们的逆操作 -? 和 -readonly),用于控制属性的只读性。
  • Partial 与映射修饰符:虽然 Partial 可以使一个类型的所有顶层属性变为可选,但对于嵌套的映射类型,直接在映射类型定义中应用 ? 提供了更细粒度的控制,尤其是在我们希望某些层级保持可选,而其他层级仍是强制时。在本文的场景中,由于是嵌套的映射类型,直接在每个映射表达式后添加 ? 是最直接有效的方案。
  • 类型安全与灵活性:这种方式在保证类型安全的同时,极大地提升了对象定义的灵活性。我们既能限制允许的键集,又能避免强制所有键都必须存在的冗余。

掌握映射类型及其修饰符是 TypeScript 高级用法中的重要一环,它能帮助我们构建出更健壮、更灵活且易于维护的代码。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

46

2026.02.13

TypeScript全栈项目架构与接口规范设计
TypeScript全栈项目架构与接口规范设计

本专题面向全栈开发者,系统讲解基于 TypeScript 构建前后端统一技术栈的工程化实践。内容涵盖项目分层设计、接口协议规范、类型共享机制、错误码体系设计、接口自动化生成与文档维护方案。通过完整项目示例,帮助开发者构建结构清晰、类型安全、易维护的现代全栈应用架构。

189

2026.02.25

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1564

2023.10.24

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

209

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

322

2024.02.23

java标识符合集
java标识符合集

本专题整合了java标识符相关内容,想了解更多详细内容,请阅读下面的文章。

292

2025.06.11

c++标识符介绍
c++标识符介绍

本专题整合了c++标识符相关内容,阅读专题下面的文章了解更多详细内容。

177

2025.08.07

treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

548

2023.12.01

Go高并发任务调度与Goroutine池化实践
Go高并发任务调度与Goroutine池化实践

本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

4

2026.03.10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
TypeScript 教程
TypeScript 教程

共19课时 | 3.4万人学习

TypeScript——十天技能课堂
TypeScript——十天技能课堂

共21课时 | 1.2万人学习

TypeScript-45分钟入门
TypeScript-45分钟入门

共6课时 | 0.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号