简体   繁体   中英

Type based on another field within an array

I want the following example to produce a type error:

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

interface Grid<T> {
  columns: {
    field: keyof T;
    formatter: (value: T[keyof T]) => string;
  }[];
}

function draw<T>(grid: Grid<T>) {}

draw<Person>({
  columns: [
    {
      field: "age",
      formatter: (value: number) => "",
    },
    {
      field: "name",
      formatter: (value: number) => "", // <-- this parameter should be a `string`! However, TS allows this because `T[keyof T]` matches.
    },
  ],
});

To what should I change the type signature for the formatter function so that its parameter matches the type of the field?

Mapped types will do:

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

// here using mapped types 
type Grid<T, Out> =
    {
        columns: {
            [K in keyof T]: 
                {
                    field: K,
                    formatter: (value: T[K]) => Out
                }
        }[keyof T][]
    }

// pay attention that it has second argument which mean the output of the formatting
function draw<T>(grid: Grid<T, string>) {}

draw<Person>({
  columns: [
    {
      field: "age",
      formatter: value => "" // value inferred as number 
    },
    {
      field: "name",
      formatter: (value: number) => "", // error as expected
    },
  ],
});

playground

Some explanation of:

type Grid<T, Out> =
    {
        columns: {
            [K in keyof T]: 
                {
                    field: K,
                    formatter: (value: T[K]) => Out
                }
        }[keyof T][]
    }
  • we map over keys of T K in keyof T
  • in every iteration we make an object which has wanted key K and wanted function from T[K] to defined output type
  • [keyof T] means that we want all values from created object by the mapped type, in result we will get union of all object with field and formatter props

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM