我正在做一个打字稿项目,在某些时候,我需要提前从microorm收集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 });
我怎么能有选项参数声明提前没有任何问题?很多谢谢!
你不能真的预先定义它并期望任何类型安全,因为它与实际值没有联系——如果你想要的话,你需要自己强制转换。或者将类型参数设置为any
,这不是很好,但实际上它是您想要的最精确的描述,因为它禁用了填充提示的严格类型。这是允许在创建这样的对象后设置更多填充提示的唯一方法。
const options: FindOneOrFailOptions<Provider, any> = { populate: ['profile'] };
options.populate.push('otherProp');
如果你只想创建一个对象,并且你知道它只包含一个项目,你可以显式传递类型值。
const options: FindOneOrFailOptions<Provider, 'profile'> = { populate: ['profile'] };
如果你不提供第二个类型参数,默认是never
-所以没有它你永远不能传递任何东西给populate
提示。