我正在研究一个项目,该项目可以在后端对动态内容进行建模,然后在前端将这些内容呈现为组件。
除了在模型中使用动态内容是联合类型的数组然后应分解为组件的模型之外,它在大多数情况下都有效。
使用普通JavaScript很容易,因为没有后顾之忧,但是我希望静态地键入组件映射器。
我的目标是创建一个映射器,使其可以使用此语法并推断类型名称(从键)和属性(从值),同时防止除ComponentType
以外的值:
// PageComponentMapper.ts
import componentMapperFactory from './componentMapperFactory'
import Hero from './Hero'
import InstagramFeed from './InstagramFeed'
import FrameBuilder from './FrameBuilder'
export default componentMapperFactory({
Hero,InstagramFeed,FrameBuilder
})
用法:
import { ComponentProps } from 'react'
import PageComponentMapper from './PageComponentMapper'
type PageComponentMapperProps = ComponentProps<typeof PageComponentMapper>
type PageContentItem =
PageComponentMapperProps['props'] &
{ key: string } &
{ type: PageComponentMapperProps['type'] }
制作中:
type PageComponentMapperProps = {
props: HeroProps | InstagramFeedProps | FrameBuilderProps,type: "Hero" | "InstagramFeed" | "FrameBuilder"
}
我走了多远? https://codesandbox.io/s/relaxed-star-6tqzz
使用此组件映射器实现:
import { createElement,ComponentType } from "react";
interface ComponentResolverProps<
ResolvableComponentTypeNames,ResolvableComponentPropTypes extends {}
> {
type: ResolvableComponentTypeNames;
props: ResolvableComponentPropTypes;
}
// How to infer type names and prop types from map?
export default function componentMapperFactory<
AvailableComponentTypeNames extends string,AvailableComponentPropTypes
>(
map: {
[K in AvailableComponentTypeNames]: ComponentType<
AvailableComponentPropTypes
>
}
) {
return function resolveComponentFromMap({
type,props
}: ComponentResolverProps<
AvailableComponentTypeNames,AvailableComponentPropTypes
>) {
const component = map[type];
if (!component) {
return null;
}
return createElement(component,props);
};
}
以前,我实际上没有提供类型名称,而是默认为字符串,这无法帮助我识别类型名称。
我也有以下想法:
export default function componentMapperFactory<
C extends { [key: string]: ComponentType }
>(
map: {
[N in keyof C]: C[N] extends ComponentType<infer P>
? (P extends unknown ? ComponentType<{}> : C[N])
: never
}
) {
return function resolveComponentFromMap({
type,props
}: {
type: keyof C;
props: ComponentProps<C["string"]>;
}) {
const component = map[type];
if (!component) {
return null;
}
return createElement(component,props);
};
}
但是这丢失了prop类型,我不知道为什么,而且在复杂的语法方面也很疯狂。
此方法的CodeSandbox:https://codesandbox.io/s/unruffled-hill-i5cbr
因此,总结一下:如何转换componentMapperFactory
,以便可以在没有显式类型参数的情况下使用它:
export default componentMapperFactory({
Hero,FrameBuilder
})
并将这些类型作为ComponentProps<typeof PageComponentMapper>
的结果吗?
type PageComponentMapperProps = {
props: HeroProps | InstagramFeedProps | FrameBuilderProps,type: "Hero" | "InstagramFeed" | "FrameBuilder"
}