【发布时间】:2021-06-09 13:25:51
【问题描述】:
我有以下文档结构:
onst blockTypes = [
'Title',
'Image',
] as const;
type BlockType = typeof blockTypes[number];
interface IDocumentBlock {
id: string;
type: BlockType;
position: number;
}
interface IConfigurableDocumentBlock<T> extends IDocumentBlock {
config: T;
}
interface ITitleBlockConfig {
size: number;
subtitle: boolean;
}
interface ITitleBlock
extends IConfigurableDocumentBlock<ITitleBlockConfig> {
type: 'Title';
content: string;
}
interface IImageBlockConfig {
alignment: 'center' | 'left' | 'right';
}
interface IImageBlock
extends IConfigurableDocumentBlock<IImageBlockConfig> {
type: 'Image';
source: string;
title?: string;
}
type DocumentBlock =
| IImageBlock
| ITitleBlock
const isConfigurableBlock = (
block: IDocumentBlock
): block is IConfigurableDocumentBlock<unknown> => {
return (block as IConfigurableDocumentBlock<unknown>).config !== undefined;
};
对于可配置的块,有一个 BlockConfigurator 类型可以传递到任何地方来配置这些块:
type BlockConfigurator<
T extends IConfigurableDocumentBlock<unknown>,
V extends keyof T['config']
> = T extends IConfigurableDocumentBlock<infer R>
? {
blockType: T['type'];
title: string;
parameter: V;
value: T['config'][V] | ((config: R) => T['config'][V]);
}
: never;
const ImageBlockConfigurator: BlockConfigurator<IImageBlock, 'alignment'> =
{
blockType: 'Image',
title: 'Right',
parameter: 'alignment',
value: (config) => (config.alignment === 'center' ? 'left' : 'right'),
};
const TitleBlockConfigurator: BlockConfigurator<ITitleBlock, 'size'> = {
blockType: 'Title',
title: 'Font Size 2',
parameter: 'size',
value: 2,
};
type Configurator =
| typeof ImageBlockConfigurator
| typeof TitleBlockConfigurator;
我在连接这两种类型时遇到了一些麻烦。我知道我得到的任何对象都是 BlockConfigurator 必须具有有效的参数和值类型,所以如果我只检查块类型,我永远不会收到错误。但是演员阵容看起来真的很丑,我想知道是否有办法编写更智能的类型保护?
const configureBlock = (block: DocumentBlock, configurator: Configurator) => {
if (
isConfigurableBlock(block) &&
block.type === configurator.blockType
) {
const value =
typeof configurator.value === 'function'
? configurator.value(block.config as any)
: configurator.value;
(block.config as any)[configurator.parameter] = value;
}
}
Here 是指向 Playground 文件的链接(如果有帮助)。
E:例如,这将消除任何强制转换,但我必须手动编写任何参数值和块类型组合:
if (
isConfigurableBlockNormalized(block) &&
block.type === configurator.blockType
) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (
configurator.blockType === 'Title' &&
configurator.parameter === 'size' &&
block.type === 'Title'
) {
const value =
typeof configurator.value === 'function'
? configurator.value(block.config)
: configurator.value;
block.config[configurator.parameter] = value;
}
}
if 块的内容对于任何组合都是完全相同的,只是条件会改变。但这些条件已融入配置器本身,并且必须为真。
【问题讨论】:
标签: javascript typescript types typeguards