typescript - Standardtyp av keyof T kan inte användas för att indexera typ T


Jag försöker refaktorera denna kod för att använda statisk metod eftersom klassen endast används som ett namnrymd och Query.equal<TodoModel>(...) är bättre än (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

Jag försökte:

class Query2 {
    static equal<T, K = keyof T>(attr: K, val: T[K]) {
        return `${String(attr)}==${val}`;
    }
}

Detta ger mig ett felmeddelande som säger att K inte kan användas för att indexera T. Varför skulle det vara så och finns det en lösning på detta?

Jag använder standardtyp eftersom med extends (equal<T, K extends keyof T>) skulle användningen vara Query2.equal<TodoModel, "title">("title", "write notes") där nyckeln behöver upprepas.

Här är hela TypeScript-lekplatsen: Länk till lekplatsen

Svar #1

Om du endast vill nämna modellen och inte typen, är den möjliga lösningen att ha en union av alla möjliga nyckel-värde-par, vilket kan uppnås med följande typ:

type UnionArgs<T> = {
  [K in keyof T]: [K, T[K]];
}[keyof T];

Användning :

// ["title", string] | ["timeLeft", number] | ["done", boolean]
type Result = UnionArgs<TodoModel>

Det enda som återstår är att uppdatera metoden/funktionen på följande sätt:

function queryEqual<T>(...args: UnionArgs<T>) {
  return `${String(args[0])}==${args[1]}`;
}

lekplats