流式细化混合功能

Flow type refine mixed to function

我正在使用 koa,它的中间件 props 类型是混合的,所以我试图按照下面的方式做一些事情,但我收到一个错误 Cannot call `ctx.render` because mixed [1] is not a function.Flow(not-a-function)

app.use(async (ctx, next) => {
  // some other code above it
  await ctx.render('index');
});

我的问题是,进行类型优化的正确方法是什么,这是一个函数,然后允许我调用它?

您可以将其细化为一个函数,但调用它是另一回事。

app.use(async (ctx, next) => {
  if (typeof ctx.render === 'function') {
    // Now we know that `ctx.render` is a function.
  }
});

Flow 实际上有一个特例,称为“未知函数”。我们知道 ctx.render 是一个函数,但我们对它的参数或 return 类型一无所知,因此除了传递它之外我们无法安全地对它做任何事情。如果我们不知道 ctx.render 接受 number,我们如何安全地调用 ctx.render(1)

更重要的是,我们无法知道任何关于它的信息。 JavaScript 没有提供反射机制,我们可以查询有关此函数的足够信息以便能够安全地调用它。我们唯一能找到的是静态元数 (ctx.render.length),但这本身并不可靠或不充分。

如果我们有更多信息,比如如果这是一个联合类型而不是 mixed,那么我们可以使用类型优化来做我们想做的事情:

(arg: boolean | (number => void)) => {
  if (typeof arg === 'function') {
    arg(1); // safe because if this is a function, we know it takes a number
  }
};

这种情况下最合理的解决办法是通过any打字。假设我们知道我们应该只接收一种类型的 render 函数,那么我们只是强行将它强制转换为该类型,并带有人们期望的所有警告:

// I don't know what the type of your render function is, but you would put it
// here:
type RenderFunction = string => void;

app.use(async (ctx, next) => {
  // some other code above it

  if (typeof ctx.render === 'function') {
    // DANGER: We make a hard assumption here that the render function is
    // always of this specific type. If it is ever of any other type then
    // behavior is undefined!
    await ((ctx.render: any): RenderFunction)('index');
  }
});

在我看来,koa libdef 可能还可以改进。