TypeScript中函数类型映射与参数类型的匹配问题
解决方案
要解决这个类型安全问题,不用as any绕过检查,我们可以通过以下两种方式优化:
方式一:精确类型断言替代any
首先明确:BlendedProps<T>是{key: T; z?: string; x?: string}与typeMap[T]的交叉类型,而typeMap[T]的键名并不包含key/z/x,因此解构后的rest类型本质上就是typeMap[T]。我们可以直接用这个精确类型做断言,而非any:
interface OneFProps { a: string; b: string; } const oneF = (props: OneFProps) => { const { a, b } = props; return `oneF ${a} ${b}`; }; interface TwoFProps { c: string; d: string; } const twoF = (props: TwoFProps) => { const { c, d } = props; return `twoF ${c} ${d}`; }; const funcMap = { oneF: oneF, twoF: twoF, }; interface typeMap { oneF: OneFProps; twoF: TwoFProps; } type tags = keyof typeMap; type BlendedProps<T extends tags> = { key: T; z?: string; x?: string; } & typeMap[T]; const blended = <T extends tags>(props: BlendedProps<T>) => { const { key, z, x, ...rest } = props; const func = funcMap[key]; // 用精确的typeMap[T]替代any,保持类型安全 return func(rest as typeMap[T]); }; console.log(blended<'oneF'>({ key: 'oneF', a: 'AAA', b: 'bbb' })); console.log(blended<'twoF'>({ key: 'twoF', c: 'ccc', d: 'DDD' }));
方式二:自动推导类型映射,减少手动维护
手动维护typeMap容易和funcMap不一致,我们可以让TypeScript自动从函数映射对象推导参数类型,同时优化泛型逻辑:
interface OneFProps { a: string; b: string; } const oneF = (props: OneFProps) => { const { a, b } = props; return `oneF ${a} ${b}`; }; interface TwoFProps { c: string; d: string; } const twoF = (props: TwoFProps) => { const { c, d } = props; return `twoF ${c} ${d}`; }; // 用as const锁定funcMap的类型,确保推导精确 const funcMap = { oneF, twoF, } as const; // 自动推导函数映射的类型 type FuncMap = typeof funcMap; type tags = keyof FuncMap; // 自动推导每个函数对应的参数类型 type typeMap = { [K in tags]: Parameters<FuncMap[K]>[0]; }; type BlendedProps<T extends tags> = { key: T; z?: string; x?: string; } & typeMap[T]; const blended = <T extends tags>(props: BlendedProps<T>) => { const { key, z, x, ...rest } = props; const func = funcMap[key]; return func(rest as typeMap[T]); }; console.log(blended({ key: 'oneF', a: 'AAA', b: 'bbb' })); // 可省略泛型参数,TypeScript自动推导 console.log(blended({ key: 'twoF', c: 'ccc', d: 'DDD' }));
原代码需要as any的原因
原代码中,TypeScript对泛型交叉类型的剩余属性推导不够精确:当你从BlendedProps<T>解构出rest时,它的类型被推断为Pick<BlendedProps<T>, Exclude<keyof BlendedProps<T>, 'key' | 'z' | 'x'>>,虽然这个类型本质上等于typeMap[T],但TypeScript无法在泛型上下文里自动确认这一点,因此需要我们用精确的类型断言来帮助它完成推导。
内容的提问来源于stack exchange,提问作者Pedro Garcia
相关产品推荐
相关产品推荐

