如何从NavigationGuard类型提取参数并省略next参数?
原始类型定义
export declare interface NavigationGuard { (to: RouteLocationNormalized, from: RouteLocationNormalized, next: NavigationGuardNext): NavigationGuardReturn | Promise<NavigationGuardReturn>; }
需求
需要生成一个移除next参数的新类型,最终期望的类型结构如下:
export type SomeNavigationGuardType = (to: RouteLocationNormalized, from: RouteLocationNormalized) => NavigationGuardReturn | Promise<NavigationGuardReturn>;
尝试的写法及问题
尝试使用Parameters工具类型提取参数,再用Omit移除next参数,但Parameters返回的是元组类型,而Omit仅适用于对象类型,无法直接操作元组,因此两种写法均报错:
第一种写法
type NavigationGuardParams = Omit<Parameters<NavigationGuard>, 'next'> export type UseRouterNivigationGuards = { beforeEach?: (arg: NavigationGuardParams) => ReturnType<NavigationGuard> beforeResolve?: (arg: NavigationGuardParams) => ReturnType<NavigationGuard> afterEach?: NavigationHookAfter }
错误提示:Expected 1 arguments, but got 2.
第二种写法
type NavigationGuardParams = Omit<Parameters<NavigationGuard>, 'next'> export type UseRouterNivigationGuards = { beforeEach?: (...arg: NavigationGuardParams) => ReturnType<NavigationGuard> beforeResolve?: (...arg: NavigationGuardParams) => ReturnType<NavigationGuard> afterEach?: NavigationHookAfter }
错误提示:Argument of type '[RouteLocationNormalized, RouteLocationNormalized]' is not assignable to parameter of type 'NavigationGuardParams'.
正确解决方案
利用TypeScript的条件类型+infer关键字提取元组的前两个元素,因为Parameters<NavigationGuard>返回的元组是[RouteLocationNormalized, RouteLocationNormalized, NavigationGuardNext],我们只需要保留前两项:
步骤1:定义移除next后的参数元组
// 提取NavigationGuard的前两个参数,忽略第三个next参数 type NavigationGuardWithoutNextParams = Parameters<NavigationGuard> extends [infer To, infer From, ...any[]] ? [To, From] : never;
步骤2:定义新的守卫类型
// 基于提取的参数元组,生成目标函数类型 type SomeNavigationGuardType = (...args: NavigationGuardWithoutNextParams) => ReturnType<NavigationGuard>;
步骤3:更新UseRouterNivigationGuards类型
export type UseRouterNivigationGuards = { beforeEach?: SomeNavigationGuardType; beforeResolve?: SomeNavigationGuardType; afterEach?: NavigationHookAfter; };
简化写法(无需单独抽类型)
也可以直接在对象类型中内联定义:
export type UseRouterNivigationGuards = { beforeEach?: (...args: Parameters<NavigationGuard> extends [infer To, infer From, ...any[]] ? [To, From] : never) => ReturnType<NavigationGuard>; beforeResolve?: (...args: Parameters<NavigationGuard> extends [infer To, infer From, ...any[]] ? [To, From] : never) => ReturnType<NavigationGuard>; afterEach?: NavigationHookAfter; };
内容的提问来源于stack exchange,提问作者Micheal J. Roberts
相关产品推荐
相关产品推荐

