TypeScript如何声明接口约束数组元素必须继承指定基础接口
TypeScript 接口强制数组成员继承指定基础接口的方案
方案1:基础无侵入实现
如果不需要对不同_type的对象做自动类型推断,直接将children声明为BaseRefs类型的数组即可,无需后续修改Document接口:
export interface Document extends BaseRefs { _createdAt: string; _rev: string; _updatedAt: string; children: BaseRefs[]; }
该方案实现最简单,后续新增任何继承BaseRefs的子类型都可以直接放入children数组,不需要调整Document的定义。缺点是操作children内的元素时,默认只能获取到_id、_ref、_type三个公共字段的类型提示,要使用专属字段需要自行通过_type判断做类型收窄。
方案2:带类型自动推断的可扩展实现
如果需要保留不同子类型的专属字段提示,同时不希望每次新增类型都修改Document接口,可以通过声明合并+类型注册的方式实现:
- 先新增全局类型注册器,用来收集所有合法的子元素类型
// 类型注册器,后续新增子类型只需要往这个接口里加声明即可 export interface RefsTypeRegistry {} // 自动生成所有已注册子类型的联合类型 export type AllowedRefs = RefsTypeRegistry[keyof RefsTypeRegistry];
- 改造
BaseRefs和子类型定义,新增子类型时同步注册到注册器
// 给BaseRefs加泛型约束_type字段的字面量类型 export interface BaseRefs<T extends string = string> { _id: string; _ref: string; _type: T; } // 定义Span类型,同时注册到注册器 export interface Span extends BaseRefs<'span'> { text: string; } declare module './你的当前ts文件名' { // 替换为当前文件的相对路径 interface RefsTypeRegistry { span: Span } } // 定义MainImage类型,同时注册到注册器 export interface MainImage extends BaseRefs<'mainImage'> { url: string; caption: string; } declare module './你的当前ts文件名' { interface RefsTypeRegistry { mainImage: MainImage } }
- 修改
Document的children类型为AllowedRefs[]
export interface Document extends BaseRefs { _createdAt: string; _rev: string; _updatedAt: string; children: AllowedRefs[]; }
后续新增子类型时,只需要在定义新类型的同时给RefsTypeRegistry加一行声明即可,不需要修改Document接口,TypeScript会自动将新类型加入children的合法类型范围,通过_type判断时也能自动收窄类型,拿到对应子类型的专属字段提示。
注:你提供的示例代码中
children内的对象缺少_id、_ref字段,如果实际业务中这两个字段确实可能不存在,可以把BaseRefs中对应字段改为可选(加?修饰符)即可。
内容的提问来源于stack exchange,提问作者user3067684
相关产品推荐
相关产品推荐

