typescript - Typescript 接口数组必须实现一个基本接口
问题描述
如何在接口中声明强制一个对象扩展另一个对象?
场景:我收到一个 JSON 对象(称为文档),其中 document.children 是一个始终具有 _id、_ref 和 _type 以及特定于其 _type 的附加字段的对象数组。
目前有 4 种不同的类型,但这会增长,理想情况下我不希望未来的开发人员担心编辑文档界面
export interface BaseRefs {
_id: string;
_ref: string;
_type: string;
}
export interface Span extends BaseRefs {
text: string;
}
export interface MainImage extends BaseRefs {
url: string;
caption: string;
}
export interface Document extends BaseRefs {
_createdAt: string;
_rev: string;
_updatedAt: string;
children: // Any object that extends BaseRefs
// children: MainImage | Span | Carousel | ........ | Video[] // This is not ideal
}
export const document: Document = {
_createdAt: '2019-12-12T04:14:18Z',
_id: 'c9b9-4cd0-a281-f6010f5889fd',
_ref: 'ej2gcz5m4',
_rev: 'nwyfsi--ej2gcz5m4',
_type: 'post',
_updatedAt: '2020-01-16T11:22:32Z',
children: [
{
_type: 'span',
text: 'The rain in Spain',
},
{
_type: 'mainImage',
url: 'https://example.com/kittens.png',
},
],
};
解决方案
如何在接口中声明强制一个对象扩展另一个对象?
你不能从字面上做到这一点。TypeScript 的类型系统是结构性的,而不是名义上的。您可以要求它具有由 定义的所有属性BaseRefs
,但实际上并非如此extends
BaseRefs
。
据我所知,类型children
应该是BaseRefs[]
:
export interface Document extends BaseRefs {
_createdAt: string;
_rev: string;
_updatedAt: string;
children: BaseRefs[];
}
这要求所有元素children
都具有由 定义的所有属性BaseRefs
。它们可以有更多的属性,这样Span
和那样MainImage
的很好,但它们至少必须具有为 定义的属性BaseRefs
。
这意味着您可以安全地使用_id
,_ref
和_type
on 中的元素children
,但是如果您尝试使用其他东西(例如Span
's 的text
属性),TypeScript 会抱怨没有text
on 属性BaseRefs
。
for (const child of someDocument.children) {
console.log(child.text);
// ^−−−−−−−−−−−−−−−−−− error here
}
那是因为它child
可能不是一个Span
,或者更一般地说,可能没有一个text
属性。
您可以通过使用类型保护来访问该属性。一种类型保护是类型保护函数,它看起来像这样:
function isSpan(x: BaseRefs): x is Span {
return "text" in x;
}
然后:
for (const child of someDocument.children) {
if (isSpan(child)) {
console.log(child.text);
// ^−−−−−−−−−−−−−−−−−− works
}
}
推荐阅读
- actionscript-3 - AS3:使用 gotoAndStop() 进行时间线导航;抛出意外的空对象错误
- c++ - 局部堆栈变量成员的返回值优化
- prism - 如何让依赖注入在 Prism for Xamarin 上工作?
- java - 使用 Maven 构建带有 res 文件夹的 jar
- c# - 为什么玩家要穿过墙壁地板门?
- android - Android Jetpack:设置 LiveData 时 RecyclerView 未更新
- css - PDFKIT 格式化页眉/页脚
- android - 如何将我的 XMPP 服务器 (ejabberd) 与 Firebase for Chat APP Android 连接
- node.js - 将 RTSP/HTTP 视频流转发到新的 HTTPS 流
- uefi - ExitBootServices 后 UEFI 硬盘访问