Typescript强制泛型类型为对象

Typescript强制泛型类型为对象,typescript,aws-lambda,Typescript,Aws Lambda,我试图创建一个泛型函数,泛型类型必须是特定的对象类型,而不仅仅是任何对象。具体地说,我试图围绕AWS Lambda handler函数创建一个包装器,为请求和响应头体定义良好的类型 以下是迄今为止我能找到的最佳解决方案: import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda'; export type AsyncHandler = (event: APIGatewayProxyEvent

我试图创建一个泛型函数,泛型类型必须是特定的对象类型,而不仅仅是任何对象。具体地说,我试图围绕AWS Lambda handler函数创建一个包装器,为请求和响应头体定义良好的类型

以下是迄今为止我能找到的最佳解决方案:

import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';

export type AsyncHandler = (event: APIGatewayProxyEvent, context: Context) => Promise<APIGatewayProxyResult>;

interface EmptyInterface {
    _?: string;
}

export type RequestQueryParameters = EmptyInterface;
export type RequestHeaders = EmptyInterface;
export type RequestBody = EmptyInterface;

export interface Request<Q extends RequestQueryParameters, H extends RequestHeaders, B extends RequestBody> {
    queryParameters: Q;
    headers: H;
    body?: B;
}

export type ResponseHeaders = EmptyInterface;
export type ResponseBody = EmptyInterface;

export interface Response<H extends ResponseHeaders, B extends ResponseBody> {
    statusCode: number;
    headers?: H;
    body: B;
}

export function createHandler<Q, H, B, RH, RB>(main: (request: Request<Q, H, B>) => Promise<Response<RH, RB>>): AsyncHandler {
    return async (event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> => {
        const response = await main({
            queryParameters: (event.queryStringParameters as unknown) as Q,
            headers: (event.headers as unknown) as H,
            body: event.body ? (JSON.parse(event.body) as B) : undefined,
        });
        return {
            statusCode: response.statusCode,
            headers: response.headers as Record<string, string> | undefined,
            body: JSON.stringify(response.body),
        };
    };
}
从“aws lambda”导入{APIGatewayProxyEvent,APIGatewayProxyResult,Context};

导出类型AsyncHandler=(事件:APIGatewayProxyEvent,上下文:context)=>Promise

对于希望允许任何内容的类型,只要它是对象而不是对象,就可以使用。类似于
B
的类型参数就是这种情况,它们的值(在底部的tsplay链接中)仅限于
any | undefined
(顺便说一句,它只是
any


对于希望确保值被约束为
字符串
未定义
的类型,以及希望支持可选属性的类型,我将创建如下类型别名:

type OptStrDict<T> = { [K in keyof T]?: string }
我将不必在这些更改中写出完整版本的代码,但您可以通过下面的游乐场链接验证这是否有效



请注意,重复使用
OptStrDict
类型别名将减少代码的详细程度,尤其是当您将其缩短为
OSD
或其他内容时。如果您认为
createHandler()
的类型签名在此之后仍然过于冗长,我不确定如何最好地继续;实际上,无论您做什么,拥有五个受约束的泛型类型参数都会占用一些空间。请考虑修改这个问题中的代码,以便构成一个当它落入独立IDE时,清楚地显示出你所面临的问题。(因此,
--strict
编译器标志和一些突出显示方法问题的代码不会出现意外错误。)这将允许希望帮助您的人立即着手解决问题,而无需首先重新创建。它将使您得到的任何答案都可以根据定义良好的用例进行测试。另外,您能解释一下
EmptyInterface
的真正意义吗?如果您试图在TypeScript中强制执行“一个特定的对象类型,而不仅仅是任何对象”,则必须在结构上表示该特定类型,因为没有。如果你不能从结构上区分一个想要的对象和一个不想要的对象,那么可能真的没有什么区别。例如,在运行时,您如何判断您是否得到了“正确”的类型?是否查看了包?@jcalz,下面是一个示例。为了澄清,我可以定义我想要的结构。我希望传递给
createHandler
的主函数具有一个具有字符串键和字符串值的响应头对象。但是假设的
main1
main2
函数都应该能够有一组不同的键。
EmptyInterface
的目的是强制每个类型(例如
ResponseHeaders
)成为一个对象,而不是字符串、数字等。
type OptStrDict<T> = { [K in keyof T]?: string }
export interface Request<
    Q extends OptStrDict<Q>,
    H extends OptStrDict<H>,
    B extends object
    > {
    queryParameters: Q;
    headers: H;
    body?: B;
}