我正在尝试设计一个类似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直接解析为符合这些接口的普通对象,而不是从普通对象中加载具体的类。
从结构上讲,Title
、Description
等接口都需要扩展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或类似的工具。