New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Constructor of a generic class cannot be assigned to a generic constructor-function type because of premature specialization #31840
Comments
As a workaround, I am trying to use a factory function instead of a constructor, but this does not work either :( // Replace CrudRepositoryCtor with CrudRepositoryFactory
export type CrudRepositoryFactory = <
T extends Entity,
Relations extends object
>(
entityClass: typeof Entity & {prototype: T},
dataSource: object,
) => EntityCrudRepository<T, Relations>;
export function crudRepositoryTestSuite(
dataSourceOptions: object,
repositoryClass: CrudRepositoryFactory,
) {
}
crudRepositoryTestSuite(
{connector: 'memory'},
<T extends Entity, Relations extends object>(entityClass, dataSource) => {
return new DefaultCrudRepository<T, Relations>(entityClass, dataSource);
}
); The compiler complains again:
Strangely enough, when add more types to the repository-factory, the compiler is able to preserve the first generic type Code: crudRepositoryTestSuite(
{connector: 'memory'},
<T extends Entity, Relations extends object>(
entityClass: typeof Entity & {prototype: T},
dataSource: object,
) => {
return new DefaultCrudRepository<T, Relations>(entityClass, dataSource);
}
); Error message:
|
If this is not a bug and the compiler behaves correctly, what's the correct way for expressing my intent? At the moment, I am able to work around the issue by using an explicit cast, which is not ideal. crudRepositoryTestSuite(
{connector: 'memory'},
DefaultCrudRepository as CrudRepositoryCtor
); I'd like to find a solution not requiring any explicit casts. |
TypeScript can't assume that two generic parameters originating in two different locations are "the same" just because they have the same names or same cardinality of parent type parameter list. Effectively, the The simpler way to examine this is with a shorter repro: export interface EntityCrudRepository<T, Relations extends object> {
findFirst(): Promise<T & Relations>;
}
declare class DefaultCrudRepository<T, Relations extends object> {
findFirst(): Promise<T & Relations>;
}
export type CrudRepositoryCtor1 = new <T, Relations extends object>() => EntityCrudRepository<T, Relations>;
declare function crudRepositoryTestSuite1(repositoryClass: CrudRepositoryCtor1): void;
crudRepositoryTestSuite1(DefaultCrudRepository);
export type CrudRepositoryCtor2 = new () => EntityCrudRepository<unknown, object>;
declare function crudRepositoryTestSuite2(repositoryClass: CrudRepositoryCtor2): void;
crudRepositoryTestSuite2(DefaultCrudRepository); Here we also see the right way to declare the |
Thank you Ryan for the answer. I'll need to spend more time to better understand what you wrote :)
IIUC your example, you are proposing to declare a new function overload for every repository class supported by the test suite. I find that problematic, because it requires the test suite to know about all possible implementations of |
TypeScript Version: 3.6.0-dev.20190608
Search Terms:
Code
Expected behavior:
The program compiles with no errors.
Actual behavior:
This part seems most relevant to me:
IIUC, the compiler is not able to treat
DefaultCrudRepository
as a generic constructor, instead if specializes the constructor function too early using "sensible" default values for generic arguments.Playground Link:
the link
Unfortunately, I am not able to reproduce the problem in the Playground.
Related Issues:
3.4.5
,3.0.3
.The text was updated successfully, but these errors were encountered: