TypeScript: Construct a typed interface based on a generic one, with the same methods but excluding the first parameter from all the functions.
Having a generic interface like:
interface GenericRepository {
insertOne<E>(entity: Type<E>, body: E): Promise<string>;
find<E>(entity: Type<E>, qm: Query<E>): Promise<E[]>;
}
interface Type<T> extends Function {
new (...args: any[]): T;
}
type Query<E> = {
[K in keyof E]: E[K];
};
class User {
firstName?: string;
}
class Company {
name?: string;
}
I'd like to be able to dynamically "produce" specific interfaces/types like:
interface UserRepository {
insertOne(body: User): Promise<string>;
find(qm: Query<User>): Promise<User[]>;
}
interface CompanyRepository {
insertOne(body: Company): Promise<string>;
find(qm: Query<Company>): Promise<Company[]>;
}
Below is what I've till now but it is not working because the entity type is not properly inferred (for the specific interfaces):
type SpecificRepository<E> = {
[K in keyof GenericRepository]: Fn<GenericRepository[K], E>;
};
type Fn<A extends (...args: any[]) => any, E> = (...a: Params<Parameters<A>>) => ReturnType<A>;
type Params<T extends any[]> = T extends [infer F, ...infer L] ? L : never;
const userRepository = {} as SpecificRepository<User>;
const companyRepository = {} as SpecificRepository<Company>;
If I do (for testing the "produced" types):
async function someMethod() {
const foundUsers = await userRepository.find({});
}
Then foundUsers is of type unknown[] but it should be User[].
How to make this properly?
Type? what isQuery? what isUser? what isCompany?). This will allow those who want to help you to immediately get to work solving the problem without first needing to re-create it. And it will make it so that any answer you get is testable against a well-defined use case.