遍历函数与Props映射的TypeScript类型匹配问题
我有一个存储React组件(对应component字段)及其对应Props(对应props字段)的映射对象,想要遍历该映射并调用component(props),但循环中TypeScript因类型范围过宽报错,示例代码及报错信息如下,如何让TypeScript识别同一对象的component与props是匹配的?
示例代码
const c1 = ({ }: { c1p1: number, c1p2: number }) => { } const c2 = ({ }: { c2p1: number }) => { } const c3 = ({ }: { c3p1: number }) => { } const components = { c1: { component: c1, props: { c1p1: 11, c1p2: 12 } }, c2: { component: c2, props: { c2p1: 21 } }, c3: { component: c3, props: { c3p1: 31 } } } const selectedComponentNames: Array<keyof typeof components> = ["c1", "c2"] selectedComponentNames.map(o => { const { component, props } = components[o] component(props) })
报错信息(翻译后)
参数类型 '{ c1p1: number; c1p2: number; } | { c2p1: number; } | { c3p1: number; }' 无法赋值给类型 '{ c1p1: number; c1p2: number; } & { c2p1: number; } & { c3p1: number; }'。
类型 '{ c1p1: number; c1p2: number; }' 无法赋值给类型 '{ c1p1: number; c1p2: number; } & { c2p1: number; } & { c3p1: number; }'。
类型 '{ c1p1: number; c1p2: number; }' 中缺少属性 'c2p1',但类型 '{ c2p1: number; }' 中需要该属性。(2345)
解决方案
方法一:用泛型函数约束单个项的类型
创建泛型函数处理每个组件键值对,让TypeScript绑定具体键对应的精确类型:
const c1 = ({ }: { c1p1: number, c1p2: number }) => { } const c2 = ({ }: { c2p1: number }) => { } const c3 = ({ }: { c3p1: number }) => { } const components = { c1: { component: c1, props: { c1p1: 11, c1p2: 12 } }, c2: { component: c2, props: { c2p1: 21 } }, c3: { component: c3, props: { c3p1: 31 } } } // 泛型函数明确当前键对应的组件与Props类型 const renderComponent = <K extends keyof typeof components>(key: K) => { const { component, props } = components[key]; component(props); }; const selectedComponentNames: Array<keyof typeof components> = ["c1", "c2"]; selectedComponentNames.map(renderComponent);
原理:泛型K会绑定到具体的键(比如"c1"),TypeScript能直接推断出该键下component和props的匹配类型,避免联合类型的冲突。
方法二:给映射对象添加精确类型定义
通过泛型接口强制每个组件项的component参数与props类型一致:
// 泛型接口约束组件和Props必须匹配 interface ComponentEntry<P> { component: (props: P) => void; props: P; } const c1 = ({ }: { c1p1: number, c1p2: number }) => { } const c2 = ({ }: { c2p1: number }) => { } const c3 = ({ }: { c3p1: number }) => { } // 明确每个键对应的ComponentEntry类型 const components: { c1: ComponentEntry<{ c1p1: number, c1p2: number }>; c2: ComponentEntry<{ c2p1: number }>; c3: ComponentEntry<{ c3p1: number }>; } = { c1: { component: c1, props: { c1p1: 11, c1p2: 12 } }, c2: { component: c2, props: { c2p1: 21 } }, c3: { component: c3, props: { c3p1: 31 } } } const selectedComponentNames: Array<keyof typeof components> = ["c1", "c2"]; selectedComponentNames.map(o => { const { component, props } = components[o]; component(props); });
原理:ComponentEntry<P>接口直接限制了每个组件项的component和props必须共享同一类型P,TypeScript能准确识别每个键对应的类型组合。
内容的提问来源于stack exchange,提问作者thesdev

