I'm building a library and having a problem inferring type dynamically.
This is library side class and useModel returns Model instance
class Database {
...
public useModel(target: Function) {
const tableName = getClassMetadata(target).name;
const table = this.config.tables.find(({ name }) => name === tableName);
// Problem is here - Not infering
type RType = typeof target extends (...args: any[]) => infer RT ? RT : Function;
// Model has selectAll() which returns RType[]
return new Model<RType>(this.connection, table);
}
}
As a library consumer, usage is shown below.
I have custom decorators to add metadata values.
@Table({ name: 'Users', timestamps: true })
class Users {
@PrimaryKey({autoIncrement: true, unique: true,})
id: number;
@Indexed({ unique: true })
@Default('John')
username: string;
@Default(0)
@Indexed({ unique: false })
age: number;
}
const database = new Database({
version: 1,
name: 'MyDatabase',
tables: [Users],
});
// I'd like Users class to be infered in useModel
const usersModel = database.useModel(Users);
usersModel.selectAll().then((users) => {
users?.forEach((user) => {
// user is not infered here :(
console.log(user);
});
});
If I use generic in useModel I know it will work but I don't want to use generic value as
const usersModel = database.useModel<typeof Users>(Users);
My goal is that Users class to be inferred automatically from useModel
This is desired usage
const usersModel = database.useModel(Users);
Any suggestions?
CodePudding user response:
You don't need a conditional type for this, a simple generic type parameter is all you need as in the following
class Database {
useModel<T>(target: new () => T): Model<T> {
const tableName = getClassMetadata(target).name;
const table = this.config.tables.find(({ name }) => name === tableName);
return new Model<T>(this.connection, table);
}
}
The reason that original version did not work is because conditional types must be determined at compile time and cannot depend on a particular path of execution.
