从构造函数选项的返回类型派生方法的回调参数的类型

时间:2020-08-03 16:47:00

标签: typescript

我正在研究Webhooks SDK。一个最小的代码示例如下所示:

const webhooks = new Webhooks({
  secret: "secret",
  path: "/webhooks"
});
webhooks.on("issues", (event) => {
  console.log(event.name); // event type is set to { name: string, payload: any }
});

Webhooks构造函数支持一个transform选项,该选项可以在将event对象传递给事件处理程序之前对其进行突变:

const webhooks = new Webhooks({
  secret: "bleh",
  path: "/webhooks",
  transform: (event) => Object.assign(event, { foo: "bar" })
});
webhooks.on("issues", (event) => {
  console.log(event.foo); // event type should be { name: string, payload: any, foo: string }
});

我的问题是:如何基于event构造函数在webhooks.on()回调中派生transform类型?

我在TypeScript playground上有一个最小的测试用例,而在pull request on the repository上有一个失败的测试

2 个答案:

答案 0 :(得分:1)

这样对您有用吗?

type WebhookEvent<T = any> = {
    name: 'string',
    payload: T
}

type TransformMethod<T extends any> = (event: WebhookEvent) => WebhookEvent<T>
// here the change using ReturnType
type EventCallback<T extends WebhookEvent> = (event: ReturnType<TransformMethod<T>>) => void
type Options<T extends WebhookEvent> = {
    transform?: TransformMethod<T>
}

class Webhooks<T extends any> {
    public on(event: string, eventHandler: EventCallback<T>) {
        // ...
    }

    constructor(options?: Options<T>) {
        // ...
    }
}

关键是将event配置为ReturnType<TransformMethod>类型,并在各处添加一些泛型

注释:

  • 如果您使用Object.assign,则transform函数返回时的键入将被放宽-它不会检查对象
  • 如果您返回PromiseLike,则该事件将返回一个对象或类似Promise的对象,因此您必须等待on中的Promise。现在,我删除了Promise部分,使其更容易,但是如果您对此进行了修改,则可以添加它

here is the playground

那你就可以做

const webhooks2 = new Webhooks<{ foo: string }>({
    transform(event) {
        return Object.assign(event, { foo: 'bar'})
    }
})
webhooks2.on('foo', event => {
    event.payload.foo
    // here autocomplete works
    console.log(event.payload.foo)
})

答案 1 :(得分:1)

这是Andrew Branch由TypeScript团队提供的解决方案:

type WebhookEvent<T = any> = {
    name: 'string',
    payload: T
}

type TransformMethod<T extends WebhookEvent> = (event: WebhookEvent) => T | PromiseLike<T>
type Options<T extends WebhookEvent> = {
    transform?: TransformMethod<T>
}

class Webhooks<T extends WebhookEvent> {
    public on(event: string, eventHandler: (event: T) => void) {
        // ...
    }

    constructor(options?: Options<T>) {
        // ...
    }
}

const webhooks1 = new Webhooks()
webhooks1.on('foo', event => {
    console.log(event.name)
})

const webhooks2 = new Webhooks({
    transform(event) {
        return Object.assign(event, { foo: 'bar'})
    }
})
webhooks2.on('foo', event => {
    console.log(event.foo)
})

TypeScript Playground