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

TypeScript中传递unknown作为泛型的类型兼容问题排查

问题:aws-lambda-router中使用ProxyIntegrationEvent泛型时报TypeScript类型不兼容错误

我在使用aws-lambda-router这个npm包,它的简化类型定义如下:

export interface APIGatewayProxyStructuredResultV2 {
    statusCode?: number;
    headers?: {
        [header: string]: boolean | number | string;
    };
    body?: string;
    isBase64Encoded?: boolean;
    cookies?: string[];
}
export interface APIGatewayProxyEvent {
    version: string;
    routeKey: string;
    rawPath: string;
    body?: string;
}
type ProxyIntegrationBody<T = unknown> = {
    body?: T;
};
type APIGatewayEventRequestContext = {
    key: string;
}
export type ProxyIntegrationEvent<T = unknown> = Omit<APIGatewayProxyEvent, 'body'> & ProxyIntegrationBody<T>
export type ProxyIntegrationResult = Omit<APIGatewayProxyStructuredResultV2, 'statusCode'> & {
    statusCode?: APIGatewayProxyStructuredResultV2['statusCode'];
};
export interface ProxyIntegrationRoute {
    path: string
    method: 'GET' | 'POST' | 'OPTIONS' | 'PUT';
    action: (
    request: ProxyIntegrationEvent<unknown>,
    context: APIGatewayEventRequestContext
    ) => ProxyIntegrationResult | Promise<ProxyIntegrationResult> | string | Promise<string>
}
export interface ProxyIntegrationConfig {
    routes: ProxyIntegrationRoute[];
}

我尝试为路由的action函数中request参数指定自定义泛型类型,但第二个路由出现了如下TypeScript错误:

Type '(request: ProxyIntegrationEvent<{ name: string; numbers: string[]; }>, context: APIGatewayEventRequestContext) => Promise<{ statusCode: number; body: string; }>' is not assignable to type '(request: ProxyIntegrationEvent<unknown>, context: APIGatewayEventRequestContext) => string | ProxyIntegrationResult | Promise<...> | Promise<...>'.
  Types of parameters 'request' and 'request' are incompatible.
    Type 'ProxyIntegrationEvent<unknown>' is not assignable to type 'ProxyIntegrationEvent<{ name: string; numbers: string[]; }>'.
      Type 'ProxyIntegrationEvent<unknown>' is not assignable to type 'ProxyIntegrationBody<{ name: string; numbers: string[]; }>'.
        Types of property 'body' are incompatible.
          Type 'unknown' is not assignable to type '{ name: string; numbers: string[]; } | undefined'.ts(2322)
Untitled-1(29, 5): The expected type comes from property 'action' which is declared here on type 'ProxyIntegrationRoute'

如果移除泛型只使用ProxyIntegrationEvent,虽然能解决编译错误,但会失去request参数的类型提示,完全浪费了泛型的作用。


原因分析

这不是你的用法错误,而是包的类型定义存在设计缺陷:当前ProxyIntegrationRoute接口的action方法被固定为接收ProxyIntegrationEvent<unknown>类型的参数。而TypeScript中函数参数是逆变的——也就是说,一个期望接收更具体类型(比如你的自定义body类型)的函数,无法被赋值给期望接收更宽泛类型(unknown)的位置,因为unknown无法安全转换为你的自定义类型。


解决方案

临时 workaround(无需修改包源码)

在action内部用类型断言转换request的类型,既能保留类型提示,又能通过编译:

const handler: ProxyIntegrationConfig = {
    routes: [
        // ...其他路由
        {
            path: '/playedGames',
            method: 'POST',
            action: async (request, context) => {
                // 转换为自定义类型
                const typedReq = request as ProxyIntegrationEvent<{ name: string, numbers: string[] }>;
                // 这里可以获得typedReq.body的类型提示
                console.log(typedReq.body?.name);
                return { statusCode: 200, body: '' };
            }
        },
    ]
};

永久修复(fork包修改类型定义)

将ProxyIntegrationRoute改为泛型接口,让每个路由可以独立指定request body的类型:

// 修改包中的ProxyIntegrationRoute定义
export interface ProxyIntegrationRoute<T = unknown> {
    path: string;
    method: 'GET' | 'POST' | 'OPTIONS' | 'PUT';
    action: (
        request: ProxyIntegrationEvent<T>,
        context: APIGatewayEventRequestContext
    ) => ProxyIntegrationResult | Promise<ProxyIntegrationResult> | string | Promise<string>;
}

// 对应的ProxyIntegrationConfig保持不变,因为TypeScript允许数组容纳不同泛型的同接口实例
export interface ProxyIntegrationConfig {
    routes: ProxyIntegrationRoute[];
}

修改后,你就能直接在定义路由时指定泛型,获得完整的类型提示且不会报错:

const handler: ProxyIntegrationConfig = {
    routes: [
        {
            path: '/playedGames',
            method: 'POST',
            action: async (request: ProxyIntegrationEvent, context) => {
                return { statusCode: 200, body: '' };
            }
        },
        {
            path: '/playedGames',
            method: 'POST',
            action: async (request: ProxyIntegrationEvent<{ name: string, numbers: string[] }>, context) => {
                return { statusCode: 200, body: '' };
            }
        },
    ]
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 21:15:58