简体   繁体   中英

Typescript : Filter on keyof type parameter

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.

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