如何让TypeScript保留React依赖props在展开时的关联关系?
React组件Props依赖关系展开时的TypeScript类型问题
我有一些React组件,接收两个存在依赖关系的props:当a为'foo'时,b必须是{ foo: number };当a为'bar'时,b必须是{ bar: number }。组件类型定义如下:
function Component< A, B extends (A extends 'foo' ? { foo: number } : { bar: number }) >(props: { a: A, b: B, }) {} <Component a="foo" b={{ foo: 1 }} /> // 合法 <Component a="bar" b={{ foo: 1 }} /> // 类型错误
我写了一个辅助函数返回这组props:
function getProps() { return Math.random() > 0.5 ? { a: 'foo', b: { foo: 1 } } : { a: 'bar', b: { bar: 1 } }; }
这个函数的返回类型被TypeScript推断为:
{ a: 'foo', b: { foo: number, bar?: undefined } } | { a: 'bar', b: { bar: number, foo?: undefined } }
但当我尝试使用<Component {...getProps()} />时,会出现类型错误,原因是TypeScript将联合类型拆解成了:
{ a: 'foo' | 'bar', b: { foo: number, bar?: undefined } | { bar: number, foo?: undefined } }
丢失了a和b之间的依赖关联。
简便解决方案
方法1:显式定义合法Props的联合类型
先定义组件接受的两种合法props组合,再让辅助函数返回这个类型,强制TypeScript保留联合成员的内部关联:
// 定义合法的props联合类型 type ValidComponentProps = | { a: 'foo', b: { foo: number } } | { a: 'bar', b: { bar: number } }; function getProps(): ValidComponentProps { return Math.random() > 0.5 ? { a: 'foo', b: { foo: 1 } } : { a: 'bar', b: { bar: 1 } }; } // 此时展开不会报错 <Component {...getProps()} />
方法2:调用时使用类型断言
如果不想修改辅助函数,可以在展开时断言为合法的联合类型:
type ValidComponentProps = | { a: 'foo', b: { foo: number } } | { a: 'bar', b: { bar: number } }; <Component {...getProps() as ValidComponentProps} />
方法3:用as const缩小返回值类型
通过as const让TypeScript精确推断返回值的字面量类型,保留a和b的关联:
function getProps() { return Math.random() > 0.5 ? ({ a: 'foo', b: { foo: 1 } } as const) : ({ a: 'bar', b: { bar: 1 } } as const); } // 若组件不接受readonly类型的props,可进一步调整为: function getProps() { return Math.random() > 0.5 ? { a: 'foo' as const, b: { foo: 1 } } : { a: 'bar' as const, b: { bar: 1 } }; }
内容的提问来源于stack exchange,提问作者Leo Jiang
相关产品推荐
相关产品推荐

