I am trying to refactor this code to use static method because the class is only used for namespace and Query.equal<TodoModel>(...)
is better than (new Query<TodoModel>).equal(...)
interface TodoModel {
title: string;
timeLeft: number;
done: boolean;
}
class Query<T> {
equal<K extends keyof T>(attr: K, val: T[K]) {
return `${String(attr)}==${val}`;
}
// other methods for notEqual, lessThan, greaterThan, contains etc.
}
let q = (new Query<TodoModel>)
q.equal("unknownKey", 45) // unknownKey gives error
q.equal("title", 765) // 765 is the wrong type
q.equal("title", "write notes") // no errors
I tried:
class Query2 {
static equal<T, K = keyof T>(attr: K, val: T[K]) {
return `${String(attr)}==${val}`;
}
}
This gives me an error saying K cannot be used to index T. Why would that be and is there a solution for this?
I use default type because with extends (equal<T, K extends keyof T>
) the usage would be Query2.equal<TodoModel, "title">("title", "write notes")
where the key needs to be repeated.
Here's the full typescript playground: Link to playground
If you want only to mention the model and not the type, the possible solution is to have a union of all possible key-value pairs, which can be achieved with the following type:
type UnionArgs<T> = {
[K in keyof T]: [K, T[K]];
}[keyof T];
Usage:
// ["title", string] | ["timeLeft", number] | ["done", boolean]
type Result = UnionArgs<TodoModel>
The only thing left is to update the method/function as follows:
function queryEqual<T>(...args: UnionArgs<T>) {
return `${String(args[0])}==${args[1]}`;
}