Type de rétrécissement de T [K] lors de l’utilisation de K étend la clé de T [dupliquer]

Nov 21 2020

J'essaye de définir une interface où:

  • une propriété est la clé d'un type générique
  • une autre propriété dépend du type de la valeur associée à cette clé de l'autre propriété

Le plus proche que je puisse obtenir est que Typescript résolve T [K] aux types d'union de toutes les valeurs de T. Mais il semble qu'il devrait y avoir un moyen de restreindre cela davantage si K est une chaîne littérale connue.

Voici un exemple de ce que j'essaie de faire.

Tester

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"
            }
        },
    ]
}

Réponses

1 CraigC Nov 21 2020 at 03:20

Suite à la question connexe liée au capitaine-yossarian, j'ai pu affiner le type en utilisant cette réponse .

Au cas où cela aiderait davantage quelqu'un, voici comment j'ai appliqué cela à mon exemple de cas.

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"
            }
        },
    ]
}