首页 > 解决方案 > Typescript 和 @octokit/webhooks.js:基于 `EmitterWebhookEventName` 约束事件类型

问题描述

我正在使用@octokit/webhooks.js具有高级泛型类型约束的包。

一个典型的用法是

webhooks.on('issue_comment.created', handlers.onIssueCommentCreated);

其中函数签名定义为

on: <E extends EmitterWebhookEventName>(event: E | E[], callback: HandlerFunction<E, TTransformed>) => void;

我正在尝试围绕该on函数创建一个辅助包装函数,如下所示,该函数目前不起作用:

function addWebhook<
  E extends (EmitterWebhookEvent<EmitterWebhookEventName> & {
    payload: { sender: User };
  })['name'] &
    `${string}.${string}`
>(webhooks: Webhooks, event: E | E[], callback: HandlerFunction<E, unknown>) {
  webhooks.on(event, (options) => {
    options.payload.sender; // <-- error: TS2339: Property 'sender' does not exist on type 'EventPayloadMap[Extract ]'.
  });
}

我想将此函数限制为仅允许E限制为EmitterWebhookEventName,并且EmitterWebhookEvent<E>['payload']['sender']类型为User。具体来说,我很难实现“这样”的逻辑。

主要的库类型有:

export declare type EmitterWebhookEventName = typeof emitterEventNames[number];
export declare type EmitterWebhookEvent<TEmitterEvent extends EmitterWebhookEventName = EmitterWebhookEventName> = TEmitterEvent extends `${infer TWebhookEvent}.${infer TAction}` ? BaseWebhookEvent<Extract<TWebhookEvent, WebhookEventName>> & {
    payload: {
        action: TAction;
    };
} : BaseWebhookEvent<Extract<TEmitterEvent, WebhookEventName>>;
interface BaseWebhookEvent<TName extends WebhookEventName> {
    id: string;
    name: TName;
    payload: WebhookEventMap[TName];
}

标签: typescriptgenericstypes

解决方案


我是@octokit/webhookslib 的维护者,我可以帮助您回答一些问题。

马上,泛型的类型E是不兼容的。它应该是string符合 的类型EmitterWebhookEventNames,而不是object

至于sender有效负载中属性的类型问题,您得到的错误是因为该sender属性并不总是出现在 webhook 有效负载中,因为E泛型没有分配给它的值,它默认为每个事件名称.

如果您以这种方式定义和使用该函数,您将能够在指定事件的回调中获取正确的有效负载类型。

import { EmitterWebhookEvent, Webhooks } from "@octokit/webhooks";
import type { EmitterWebhookEventName, HandlerFunction } from "@octokit/webhooks/dist-types/types"
import type { User } from "@octokit/webhooks-types"

const webhooks = new Webhooks({secret: 'foo'});

function addWebhook<E extends EmitterWebhookEventName>(webhooks: Webhooks, event: E | E[], callback: HandlerFunction<E, unknown>) {
  webhooks.on(event, callback);
}

addWebhook(webhooks, "issue_comment.created", (options) => {
  options.payload.sender; // type is User
})

推荐阅读