You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现无需手动指定泛型的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属性
  }
});

核心原理

  1. 元组类型推断:createApp函数接收的authMethods参数用[...T]约束为元组,TypeScript会保留每个元素的具体类型信息,而非合并为联合类型。
  2. 映射类型提取:ExtractAuthTypes工具类型遍历元组中的每个认证方法,提取type作为键,推导getContext返回值作为对应的上下文类型,生成认证类型与上下文的映射。
  3. 自动泛型推导:无需手动指定泛型参数,TypeScript会从传入的authMethods数组自动推断出T类型,进而生成AuthTypes映射,实现强类型约束。

这种方案既满足了「禁止配置未定义认证类型」「Guard参数匹配对应上下文」的核心需求,又完全避免了手动指定泛型的繁琐,同时保持了类型系统的严谨性。

内容的提问来源于stack exchange,提问作者Pokkke

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:55:13