Ein enger Typ von T [K] bei Verwendung von K erweitert den Schlüssel von T [Duplikat]

Nov 21 2020

Ich versuche eine Schnittstelle zu definieren, in der:

  • Eine Eigenschaft ist der Schlüssel eines generischen Typs
  • Eine andere Eigenschaft hängt vom Typ des Werts ab, der diesem Schlüssel aus der anderen Eigenschaft zugeordnet ist

Das nächste, was ich bekommen kann, ist, dass Typescript T [K] zu den Vereinigungstypen aller Werte von T auflöst. Es scheint jedoch eine Möglichkeit zu geben, dies weiter einzugrenzen, wenn K ein bekanntes String-Literal ist.

Hier ist ein Beispiel dafür, was ich versuche zu tun.

Prüfung

interface Person {
    age: number;
    name: string;
}

interface ColumnDef<T, K extends keyof T> {
    key: K;
    renderData: (value: T[K]) => void;
}

interface Report<T> {
    columns: ColumnDef<T, keyof T>[];
}

const report: Report<Person> = {
    columns: [
        {
            key: "age", // this is correctly typed to be "age"|"name"
            renderData: (value) => {
                // ideally value should be "number" here, but it is "string|number"
            }
        },
        {
            key: "name", // this is correctly typed to be "age"|"name"
            renderData: (value) => {
                // ideally value should be "string" here, but it is "string|number"
            }
        },
    ]
}

Antworten

1 CraigC Nov 21 2020 at 03:20

Nach der verwandten Frage von Captain-Yossarian konnte ich den Typ anhand dieser Antwort eingrenzen .

Falls es jemandem weiter hilft, habe ich das hier auf meinen Beispielfall angewendet.

interface Person {
    age: number;
    name: string;
}

type ColumnDef<T> = {
    [K in keyof T]-?: BaseColumnDef<T, K>
  }[keyof T]


interface BaseColumnDef<T, K extends keyof T> {
    key: K;
    renderData: (value: T[K]) => void;
}

interface Report<T> {
    columns: ColumnDef<T>[];
}

const report: Report<Person> = {
    columns: [
        {
            key: "age", // this is correctly typed to be "age"|"name"
            renderData: (value) => {
                // value is now type "number"
            }
        },
        {
            key: "name", // this is correctly typed to be "age"|"name"
            renderData: (value) => {
                // value is now type "string"
            }
        },
    ]
}