Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I specify a const list of of keys, and derive a Picked interface from that list, in a type-safe way?

I have a predefined and complex interface which I cannot manipulate since it comes from a third party library.

interface Fruit {
    name?: string;
    id?: number;
    weight?: number;
}

I need to

  • Define a list of a subset of the keys of that interface, and then
  • Define a new interface (or type) which will have just those^ members, which will be typed the same as the original interface.

To clarify: I need to actually use the list in my code (otherwise I would just write them into a Pick<Fruit, ...> and be done with it).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Here is one approach:

const fieldsToIsolate = ["id", "weight"] as const;

type IsolatedFruit = Pick<Fruit, typeof fieldsToIsolate[number]>;
// type IsolatedFruit = {
//     id?: number | undefined;
//     weight?: number | undefined;
// }

The problem with this approach is that fieldsToIsolate is not type-safe.

Here is a different approach which solves that, but has its own problem:

const fieldsToIsolate: Array<keyof Fruit> = ["id", "weight"];

type IsolatedFruit = Pick<Fruit, typeof fieldsToIsolate[number]>;
// type IsolatedFruit = {
//     name?: string | undefined;
//     id?: number | undefined;
//     weight?: number | undefined;
// }

Now the list is safely typed, but IsolatedFruit is not accurate.

Typescript now complains if we try to re-attach as const, because

The type 'readonly ["id", "weight"]' is 'readonly' and cannot be assigned to the mutable type '(keyof Fruit)[]'

Is there a way to achieve this?

>Solution :

I would do this with the satisfies keyword, which was introduced in typescript 4.9:

const fieldsToIsolate = ["id", "weight"] satisfies Array<keyof Fruit>;

type IsolatedFruit = Pick<Fruit, typeof fieldsToIsolate[number]>;

This causes typescript to do 2 things:

  1. fieldsToIsolate will get a more specific type than string[], based on the exact values you used. In this example, the type will be ('id' | 'weight')[]. This in turn allows IsolatedFruit to be the correct type.
  2. Typescript will check to verify that "id" and "weight" are indeed keys of Fruit and will give an error if they are not. So typos and nonexistent keys will be brought to your attention.

Playground link

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading