为何TypeScript在普通函数与React组件中的表现存在差异?
React组件中Renders类型的Props参数提示失效问题
问题代码
type Block = { blockName: string } type Parsers = Record<string, (block: Block) => object> type Renders<T> = { [key in keyof T]: (props: ReturnType<T[key] extends Parsers[string] ? T[key] : never>) => string } const Blocks = <P extends Parsers>(props: { parsers: P renders: Renders<P> }) => { return null }
这段代码在普通TypeScript环境下类型推断正常,但作为React组件调用时,renders中每个函数的props参数无法得到精确的类型提示,只能识别为object类型。
问题原因
核心问题在于Parsers类型使用了Record<string, (block: Block) => object>的宽泛索引签名。当泛型P约束为Parsers时,TypeScript会将P的所有属性统一推断为(block: Block) => object,丢失了每个parser函数具体的返回类型信息,导致Renders中的ReturnType无法提取精确的结构,最终props提示失效。
解决方案
修改泛型约束方式,让TypeScript保留每个parser函数的具体返回类型:
type Block = { blockName: string } // 直接在泛型约束中定义parser结构,避免宽泛的Record索引签名 type Renders<T> = { [key in keyof T]: (props: ReturnType<T[key]>) => string } const Blocks = <P extends { [K in keyof P]: (block: Block) => object }>(props: { parsers: P renders: Renders<P> }) => { return null }
验证示例
调用组件时,renders中的props会自动获得精确的类型提示:
Blocks({ parsers: { text: (block) => ({ content: block.blockName, size: 16 }), image: (block) => ({ src: 'test.jpg', alt: block.blockName }) }, renders: { text: (props) => { // 正确提示props.content(string类型)和props.size(number类型) return `<div style="font-size: ${props.size}px">${props.content}</div>` }, image: (props) => { // 正确提示props.src和props.alt(均为string类型) return `<img src="${props.src}" alt="${props.alt}" />` } } })
备选方案(保留Parsers类型)
如果需要保留Parsers类型定义,可以将其改为泛型形式,避免固定的索引签名:
type Block = { blockName: string } type Parsers<T extends string> = { [K in T]: (block: Block) => object } type Renders<T> = { [key in keyof T]: (props: ReturnType<T[key]>) => string } const Blocks = <T extends string, P extends Parsers<T>>(props: { parsers: P renders: Renders<P> }) => { return null }
内容的提问来源于stack exchange,提问作者Dez64ru
相关产品推荐
相关产品推荐

