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).
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:
fieldsToIsolatewill get a more specific type thanstring[], based on the exact values you used. In this example, the type will be('id' | 'weight')[]. This in turn allowsIsolatedFruitto be the correct type.- Typescript will check to verify that "id" and "weight" are indeed keys of
Fruitand will give an error if they are not. So typos and nonexistent keys will be brought to your attention.