I want to implement a type map that ensures the type of an object's value for a specific key is determined by the value of another key. For example:
type CurrencyValue = {
code: string;
value: number;
};
type FieldMap = {
text: string;
currency: CurrencyValue;
};
type FieldKind = keyof FieldMap;
type Field<T extends FieldType> = {
kind: FieldKind;
value: FieldMap[T];
};
In this scenario, if I create an object with the structure Field
, and its kind
is set to "text", then the expected type of value
should be a string
. If the kind
is "currency", then the value
should match the CurrencyValue
type.
While I can almost achieve this functionality with the existing setup, I find myself needing to specify a parameter in the type:
// this works
const field: Field<"currency"> = {
type: "currency",
value: {
code: "USD",
value: 12,
},
};
// this doesn't
// error: Generic type 'Field' requires 1 type argument(s).ts(2314)
const field: Field = {
type: "currency",
value: {
code: "USD",
value: 12,
},
};
However, I wish to avoid having to explicitly define the type parameter in these cases. Is there a way for TypeScript to infer the type of value
without explicit declaration?
One approach that has worked for me involves using discriminated unions:
type CurrencyField = {
type: 'currency',
value: CurrencyValue;
}
type TextField = {
type: 'text',
value: string;
}
type Field = CurrencyField | TextField;
const field: Field = {
type: 'text',
value: 'string'
}
However, creating multiple new types whenever a new version of a Field
is introduced is not ideal. Therefore, it would be more convenient to simply update the mapping.
Thank you for your assistance!