如何在不使用对象联合类型时严谨定义TypeScript的MediaData类型
解决方案:严谨定义MediaData类型(不使用手动对象联合)
方案一:泛型+条件类型实现类型绑定
通过泛型关联type字段取值,搭配条件类型自动匹配对应meta类型,既保证类型严谨性,又避免手动编写对象联合分支:
// 定义媒体类型的字面量联合 type MediaType = 'audio' | 'video'; // 根据type字段自动推导对应的meta类型 type MediaMeta<T extends MediaType> = T extends 'audio' ? AudioMeta : VideoMeta; // 最终的MediaData泛型类型 type MediaData<T extends MediaType = MediaType> = { type: T; meta: MediaMeta<T>; };
使用示例
// 指定类型时,meta会强制匹配对应结构 const audioData: MediaData<'audio'> = { type: 'audio', meta: { rate: 44100, codec: 'mp3', duration: 120 } // 必须符合AudioMeta结构 }; const videoData: MediaData<'video'> = { type: 'video', meta: { width: 1920, height: 1080, codec: 'h264', duration: 120 } // 必须符合VideoMeta结构 }; // 不指定类型时,自动推导为严谨的联合类型 const mediaData: MediaData = Math.random() > 0.5 ? audioData : videoData;
方案二:映射类型自动生成严谨联合类型
如果场景允许使用联合类型,但不想手动编写每个对象分支,可通过映射类型自动生成等价的严谨联合类型:
// 建立媒体类型与元数据类型的映射关系 type MediaMetaMap = { audio: AudioMeta; video: VideoMeta; }; // 基于映射类型生成最终的MediaData type MediaData = { [K in keyof MediaMetaMap]: { type: K; meta: MediaMetaMap[K]; }; }[keyof MediaMetaMap];
该方式生成的MediaData与你原本手动编写的对象联合类型完全等价,但维护性更强——后续新增媒体类型时,只需修改MediaMetaMap即可。
补充:非联合结构的运行时校验
如果场景必须使用type和meta均为联合类型的单一对象结构,可通过类型守卫在运行时校验,配合类型定义实现严谨性:
// 类型守卫函数,判断meta是否属于AudioMeta function isAudioMeta(meta: AudioMeta | VideoMeta): meta is AudioMeta { return 'rate' in meta; } // 业务逻辑中使用类型守卫做类型推断 function processMedia(data: MediaData) { if (data.type === 'audio' && isAudioMeta(data.meta)) { // 此处data.meta会被TS推断为AudioMeta console.log(data.meta.rate); } else if (data.type === 'video') { // 此处data.meta会被TS推断为VideoMeta console.log(data.meta.width); } }
内容的提问来源于stack exchange,提问作者vaseala
相关产品推荐
相关产品推荐

