TypeScript中如何正确推断作为入参传入的函数的参数类型
问题背景
- 需求:实现支持可选第二参数的
useTheme函数,传入样式函数后,useTheme需要根据样式函数的参数类型,自动校验自身styleProps入参的静态类型。 - 原有实现存在类型推断缺陷:当样式函数的第二参数是联合类型时,合法传参会被标记为类型错误。
原有问题代码如下:
type StylingFn<T, P> = ( theme: Theme, ...props: P extends undefined ? [undefined?] : [P] ) => StyleProp<T>; const useTheme = <T, P = undefined>( styles: StylingFn<T, P>, ...styleProps: P extends undefined ? [undefined?] : [P] ) => { const theme: Theme = {}; // 示例代码 return styles(theme, ...styleProps); }; // 问题复现 const Union = "a" | "b"; const s1 = (theme: Theme) => ({}); const s2 = (theme: Theme, {c}: {c: number}) => ({}); const s3 = (theme: Theme, {c}: {c: Union}) => ({}); useTheme(s1); // 校验通过 useTheme(s2, {c: 12}); // 校验通过 useTheme(s3, {c: "a"}); // 误报错误
问题原因
原有实现通过独立泛型P同时约束StylingFn和styleProps的类型,TypeScript在类型推断阶段会优先匹配StylingFn的类型结构,遇到联合类型等复杂类型时会出现推断偏差,丢失类型信息,导致校验错误。
修复方案
通过infer关键字直接从传入的样式函数中提取剩余参数类型,避免提前用泛型约束打断类型推断链路,完整保留参数的原始类型信息。
type Theme = Record<string, any>; type StyleProp<T> = T; // 从传入的样式函数中提取额外参数类型 type ExtractStyleProps<StyleFn> = StyleFn extends (theme: Theme, ...args: infer Props) => StyleProp<any> ? Props : never; const useTheme = <StyleFn extends (theme: Theme, ...args: any[]) => StyleProp<any>>( styles: StyleFn, ...styleProps: ExtractStyleProps<StyleFn> ) => { const theme: Theme = {}; // 业务逻辑替换为实际theme获取逻辑 return styles(theme, ...styleProps); };
验证结果
以下用例均符合类型校验预期:
const Union = "a" | "b"; const s1 = (theme: Theme) => ({}); const s2 = (theme: Theme, {c}: {c: number}) => ({}); const s3 = (theme: Theme, {c}: {c: Union}) => ({}); useTheme(s1); // 校验通过 useTheme(s2, {c: 12}); // 校验通过 useTheme(s3, {c: "a"}); // 校验通过 useTheme(s3, {c: "c"}); // 正常报错:类型"c"不在联合类型"a"|"b"范围内
内容的提问来源于stack exchange,提问作者nickfla1
相关产品推荐
相关产品推荐

