Let's say I have an interface like this:
interface Cat {
weight: number;
name: string;
adoptable: boolean;
}
I want to define the following interface that can be used to set values on Cat
:
interface CatUpdate {
field: keyof Cat;
value: ???
}
and I want TypeScript to enforce that value is the appropriate type based on field. E.g., this should be invalid:
const x: CatUpdate = {
field: "name",
value: 12
}
How do I define the type of CatUpdate.value
?
My inclination would be to make CatUpdate
a union type and not an interface, like this:
interface Cat {
weight: number;
name: string;
adoptable: boolean;
}
type PropUpdate<T extends object> = {
[K in keyof T]: { field: K; value: T[K] }
}[keyof T];
type CatUpdate = PropUpdate<Cat>;
/*
type CatUpdate = {
field: "weight";
value: number;
} | {
field: "name";
value: string;
} | {
field: "adoptable";
value: boolean;
}
*/
That should work well enough on your mentioned use case:
const x: CatUpdate = {
field: "name",
value: 12
} // error!
And you should be able to compose those (CatUpdate | DogUpdate
) if you need to, although without a particular use case it's hard to know if such composition is appropriate (Can Cat
and Dog
be discriminated from each other? That is, is Cat & Dog
impossible? If Cat & Dog
is possible, then CatUpdate | DogUpdate
can only be used to update a Cat & Dog
. If it's impossible, then CatUpdate | DogUpdate
should probably be replaced with a discriminated union instead like (CatUpdate & {kind: "CatUpdate"}) | (DogUpdate & {kind: "DogUpdate"})
.)
Hope that helps; good luck!
Link to code
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With