不同类型块的结构化类型



我正在尝试设计一个类似CMS的块系统,其中的输入是一些JSON:

[{
type: "title",
text: "hello"
}, {
type: "description",
text: "world"
}, {
type: "button",
text: "Click Me",
href: "/"
}]

我会定义";块";键入这样的系统:

namespace Blocks {
interface Title {
type: "title";
text: string;
}
interface Description {
type: "description";
text: string;
}  
interface Button {
type: "button";
text: string;
href: string;
color?: string;
}
}

我将如何构建它,以便我可以通过一个通用的";块";类型,哪个将根据type进行类型检查?或者这是一种错误的构建方式?

interface Page {
blocks: Block[]
}
interface Block extends AnyOfThoseBlocks { // how would I extend all types of the namespace?
blocks?: Block[]; // blocks can contain nested other blocks
}

我认为您希望将JSON直接解析为符合这些接口的普通对象,而不是从普通对象中加载具体的类。

从结构上讲,TitleDescription等接口都需要扩展Block接口,而不是反过来。这样,它们将继承blocks属性。所以,也许:

interface Block {
type: string;
blocks: Block[];
}
namespace Blocks {
export interface Title extends Block { type: 'title'; /* ... */ }
export interface Description extends Block { type: 'description'; /* ... */ }
export interface Button extends Block { type: 'button'; /* ... */ }
}

如果您在某个地方有一个类型为Block的对象,您可以检查其type字段,并基于此将其强制转换到适当的接口:

function logHref(block: Block): void {
if (block.type === 'button') {
console.log((block as Blocks.Button).href);
}
}

请记住,您无法通过这种方式实现真正的类型安全,因为您的JSON可能会以某种方式包含一个格式错误的对象,如{"type":"button","text":"Hello World"}(缺少href(。为了适当的安全,你可以使用ajv或类似的工具。

最新更新