Zwężenie typu T [K] przy użyciu K wydłuża klucz T [duplikat]

Nov 21 2020

Próbuję zdefiniować interfejs, w którym:

  • jedna właściwość jest kluczem typu ogólnego
  • inna właściwość zależy od typu wartości skojarzonej z tym kluczem z innej właściwości

Najbliższe, jakie mogę uzyskać, to rozwiązanie T [K] przez Typescript do typów unii wszystkich wartości T. Wygląda jednak na to, że powinien istnieć sposób na dalsze zawężenie tego, jeśli K jest znanym literałem ciągu.

Oto przykład tego, co próbuję zrobić.

Test

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

Odpowiedzi

1 CraigC Nov 21 2020 at 03:20

Podążając za pokrewnym pytaniem związanym z kapitanem Yossarianem, byłem w stanie zawęzić typ za pomocą tej odpowiedzi .

Na wypadek, gdyby to komuś pomogło, oto jak zastosowałem to w moim przykładowym przypadku.

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