I'm using typescript 3.8.3 and try to dynamically find the keys of a certain type and use them to produce an other object.
I have a Detail
object and want to use it to dynamically generate a Column
object only based on the properties of type Desc
. Here is a simplified code of what i want to do:
// Model
interface Desc {
creationDate: Date;
}
interface Address extends Desc {
zipCode: number;
adressName: string;
}
interface Order extends Desc {
id: number;
orderName: string;
}
interface Detail {
name: string;
address: Address[];
orders: Order[];
}
// Table column configuration
interface Column<T> {
field: keyof T;
active: boolean;
}
type ColumnConfig<T> = { [P in keyof T]: Column<T[P] extends Desc ? P : never>[] };
const config: ColumnConfig<Detail> = {
address: [
{
field: "zipCode",
active: true
},
{
field: "addressName",
active: true
}
],
order: [
{
field: "id",
active:false
},
{
field: "orderName",
active: false
}
],
// Detail.name should not be available but it is
}
How can i benefit from the help of the compiler to construct my config
object and thus be able to detect any errors if my Detail
object changes?
Thanks !
In order to exclude some columns for a mapped type, we need to use an intermediate helper type, allowing us to select only the keys respecting our condition, T[K] extends Desc
:
type ConfigurableColumnsKeys<T extends object> = {
[K in keyof T]: T[K] extends Desc ? K : never
}[keyof T];
Given this, ColumnConfig
just need to map over this generic type instead of the original keyof T
:
type ColumnConfig<T extends object> = {
[P in ConfigurableColumnsKeys<T>]: Column<P>[]
};
Then your config object will be correctly validated:
// Error
name: [
{ field: 'abc', active: true }
]
If you need to allows arrays too (ie Address[]
instead of Address
), you can change the helper type, checking for T extends Desc[]
. Furthermore, you will need an UnboxArray
helper too, to extract item value Order[]
-> Order
for your column config:
type ConfigurableColumnsKeys<T extends object> = {
[K in keyof T]: T[K] extends Desc ? K : T[K] extends Desc[] ? K : never
}[keyof T];
type UnboxArray<T> = T extends Array<infer V> ? V : T;
type ColumnConfig<T extends object> = {
[P in ConfigurableColumnsKeys<T>]: Column<UnboxArray<T[P]>>[]
};
You can see it at work in the following playground: Playground Link
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.