如何属性键入MikroORM FindOneOrFailOptions 参数提前收集

How to property type the MikroORM FindOneOrFailOptions parameter to collect it in advance

我正在做一个打字稿项目,在某些时候,我需要提前从 MikroORM 收集 FindOneOrFailOptions 参数。

代码要复杂得多,但我设法用更少的行复制了这个问题。

虽然这段代码没有问题:

class ProviderRepository {
   public async findOneByUrl(url: string): Promise<Provider> {
      const repository = /* is of type EntityRepository<Provider> */
      return await repository.findOneOrFail({ url }, { populate: ['profile'] });
    }
}

下面一个因加注 TS2345: Argument of type '{ populate: string[]; }' is not assignable to parameter of type 'FindOneOrFailOptions<Provider, string>'. 而失败:

class ProviderRepository {
   public async findOneByUrl(url: string): Promise<Provider> {
      const repository = /* is of type EntityRepository<Provider> */

      const options = { populate: ['profile'] };
      return await repository.findOneOrFail({ url }, options);
                                                     -------
    }
}

嗯,果然解决方案应该是将 options 声明为 FindOneOrFailOptions<Provider, string>。但是,如果我这样做,则会引发 TS2322: Type 'string' is not assignable to type 'never'.:

class ProviderRepository {
   public async findOneByUrl(url: string): Promise<Provider> {
      const repository = /* is of type EntityRepository<Provider> */

      const options: FindOneOrFailOptions<Provider, string> = { populate: ['profile'] };
                                                                           ---------
      return await repository.findOneOrFail({ url }, options);
    }
}

此时我对如何进行有点迷茫。 我假设那里的 never 来自函数声明:

class EntityRepository<T extends AnyEntity<T>> {
    findOneOrFail<P extends string = never>(where: FilterQuery<T>, options?: FindOneOrFailOptions<T, P>): Promise<Loaded<T, P>>;
}

然而,即使我像repository.findOneOrFail<string>(...)一样使用这个函数,它仍然会产生同样的错误。 我认为必须有某种自动转换,就像我内联参数一样,即使没有 <string>,它也很乐意毫无问题地接受它。这告诉我,我还没有确定它期望的确切类型,但我对这种类型可能是什么一无所知。

如何才能毫无问题地提前声明 options 参数?非常感谢!

它不能只键入 string,如果我们允许,我们将失去类型安全性,因为可以使用任何字符串。它需要是具有实际值的字符串文字类型。对于您的特定用例,const 断言应该可以完成这项工作:

await repository.findOneOrFail({ url }, { populate: ['profile'] as const });

How can I have the options parameter declared in advance without any issue? Many thanks!

您不能真正预先定义它并期望任何类型的安全性,因为它与实际值没有关系 - 如果需要,您需要自己进行转换。或者将类型 arg 设置为 any,这不是很好,但实际上它是您想要的最精确的描述,因为它禁用了填充提示的严格类型。这是在创建此类对象后允许设置更多填充提示的唯一方法。

const options: FindOneOrFailOptions<Provider, any> = { populate: ['profile'] };
options.populate.push('otherProp');

如果您只想创建对象并且知道它只会包含一项,则可以显式传递类型值。

const options: FindOneOrFailOptions<Provider, 'profile'> = { populate: ['profile'] };

如果你不提供第二个类型的参数,默认是 never - 所以没有它你永远不能将任何东西传递给 populate 提示。