如何实现无需手动指定泛型的TypeScript关联类型约束?
无需手动指定泛型的实现方案
通过TypeScript的自动类型推断和元组类型提取,可以实现完全无需手动指定泛型的约束方案。核心思路是通过传入的认证方法集合,让TypeScript自动推导认证类型与上下文的映射关系,进而约束路由Guard的配置。
实现代码
// 单个认证方法的结构:包含类型标识和上下文生成函数 type AuthMethod<TType extends string, TContext> = { type: TType; getContext: () => TContext; }; // 从认证方法元组中提取「认证类型 → 上下文」的映射类型 type ExtractAuthTypes<T extends AuthMethod<string, any>[]> = { [K in T[number]['type']]: Extract<T[number], { type: K }>['getContext'] extends () => infer C ? C : never; }; // 创建应用的工厂函数,自动推断认证类型映射 function createApp<T extends AuthMethod<string, any>[]>(authMethods: [...T]) { // 自动推导的认证类型-上下文映射 type AuthTypes = ExtractAuthTypes<T>; // Guard类型:仅允许已定义的认证类型,且handler参数匹配对应上下文 type Guard<TType extends keyof AuthTypes> = (context: AuthTypes[TType]) => boolean; // 路由配置类型:约束Guard只能使用已定义的认证类型 type RouteConfig = { path: string; guard?: { type: keyof AuthTypes; handler: Guard<typeof guard.type> }; }; return { addRoute(route: RouteConfig) { // 这里可以实现路由注册的逻辑 console.log('Registered route:', route.path); } }; }
使用示例
// 初始化应用时传入具体的认证方式,无需手动指定泛型 const app = createApp([ { type: 'jwt', getContext: () => ({ userId: 'user_123', role: 'admin' }) }, { type: 'apikey', getContext: () => ({ apiKey: 'abc_456', scope: 'read_write' }) } ]); // ✅ 合法配置:Guard使用已定义的jwt类型,handler参数自动匹配上下文 app.addRoute({ path: '/admin/dashboard', guard: { type: 'jwt', handler: (ctx) => ctx.role === 'admin' // ctx类型自动推断为{ userId: string; role: string } } }); // ✅ 合法配置:使用apikey类型,handler参数匹配对应上下文 app.addRoute({ path: '/api/data', guard: { type: 'apikey', handler: (ctx) => ctx.scope.includes('read') // ctx类型自动推断为{ apiKey: string; scope: string } } }); // ❌ 非法配置:使用未定义的oauth类型,TypeScript直接报错 app.addRoute({ path: '/oauth/login', guard: { type: 'oauth', // 类型错误:"oauth"不在"jwt" | "apikey"中 handler: (ctx) => true } }); // ❌ 非法配置:handler参数类型不匹配,TypeScript报错 app.addRoute({ path: '/api/secret', guard: { type: 'apikey', handler: (ctx) => ctx.role === 'admin' // 错误:ctx不存在role属性 } });
核心原理
- 元组类型推断:
createApp函数接收的authMethods参数用[...T]约束为元组,TypeScript会保留每个元素的具体类型信息,而非合并为联合类型。 - 映射类型提取:
ExtractAuthTypes工具类型遍历元组中的每个认证方法,提取type作为键,推导getContext返回值作为对应的上下文类型,生成认证类型与上下文的映射。 - 自动泛型推导:无需手动指定泛型参数,TypeScript会从传入的
authMethods数组自动推断出T类型,进而生成AuthTypes映射,实现强类型约束。
这种方案既满足了「禁止配置未定义认证类型」「Guard参数匹配对应上下文」的核心需求,又完全避免了手动指定泛型的繁琐,同时保持了类型系统的严谨性。
内容的提问来源于stack exchange,提问作者Pokkke
相关产品推荐
相关产品推荐

