如何在 TypeScript 中传递基于可变参数类型的类型?

问题描述 投票:0回答:1

TypeScript 游乐场链接

我正在为项目的 Express 创建一个路由处理程序创建器,并且我正在尝试创建它,以便您可以在传递路由处理程序回调之前传递任意断言作为初始参数。像这样的东西:

const myHandler = makeHandler(assertion1(), assertion2(), (data, req, res, next) => {
  // data is an array of the results of the assertions
});

我可以获得我想要的类型“工作”方式的某种版本:

// express namespace omitted for brevity; see playground link above.

type Assertion<T = unknown> = (req: express.Request) => T;
type ReturnTypes<A extends ReadonlyArray<Assertion>> = {
  [K in keyof A]: ReturnType<A[K]>;
};

function assertion1<T extends object>(arg: T) {
  return function inner(req: express.Request): T {
    return arg;
  }
}

function assertion2() {
  return function inner(req: express.Request): string {
    return "yes"
  }
}

const a = assertion1({ something: "yes" })
const b = assertion2()

// This type works as expected: it is [{ something: string }, string]
type d = ReturnTypes<[typeof a, typeof b]>

但是,当我尝试让它作为上述

makeHandler
参数的可变参数版本工作时,有些东西似乎不起作用,上面示例中
data
的类型是
unknown[]
:

function makeHandler<
  Assertions extends Assertion[],
  R = ReturnTypes<Assertions>,
>(...assertionsAndCb: [...Assertions, HandlerCb<R>]) {
  return async function handlerImpl(
    req: express.Request,
    res: express.Response,
    next: express.NextFunction
  ) {
    const assertions = assertionsAndCb.slice(0, -1) as Assertions;
    const [cb] = assertionsAndCb.slice(-1) as [HandlerCb<R>];

    const data = [];

    for (const assertion of assertions) {
      try {
        data.push(assertion(req));
      } catch (e) {
        next(e);

        return;
      }
    }

    try {
      await cb(data as R, req, res, next);
    } catch (e) {
      next(e);
    }
  };
}

// `data` here doesn't seem to work, though. For some reason it's of type unknown[], rather than 
// the same as type `d` above.
makeHandler(assertion1({ hey: "what"}), assertion2(), (data, req) => {
  return { response: {} }
})

我已经读过一些关于这如何适用于像

zip
这样的东西(并且我的函数很大程度上基于这个要点),但我正在努力让实际类型正确通过。我在这里遗漏了一些东西吗?例如,我没有正确地允许推断一些通用的东西?

typescript variadic-functions
1个回答
0
投票
function makeHandler<
  Assertions extends Assertion[],
  R = ReturnTypes<Assertions>,
>(...assertionsAndCb: [...Assertions, HandlerCb<R>]) : (
  ...args: [...Assertions, HandlerCb<R>]
) => ReturnType<HandlerCb<R>> {
  return async function handlerImpl(
    req: express.Request,
    res: express.Response,
    next: express.NextFunction
  ) {
    const assertions = assertionsAndCb.slice(0, -1) as Assertions;
    const [cb] = assertionsAndCb.slice(-1) as [HandlerCb<R>];

    const data = [];

    for (const assertion of assertions) {
      try {
        data.push(await assertion(req));
      } catch (e) {
        next(e);

        return;
      }
    }

    try {
      await cb(data as R, req, res, next);
    } catch (e) {
      next(e);
    }
  };
}
© www.soinside.com 2019 - 2024. All rights reserved.