Reputation: 30202
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?
Upvotes: 0
Views: 563
Reputation: 20132
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
},
],
});
Some explanation of:
type Grid<T, Out> =
{
columns: {
[K in keyof T]:
{
field: K,
formatter: (value: T[K]) => Out
}
}[keyof T][]
}
K in keyof T
[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 propsUpvotes: 3