How to do Typesafe JSON with fields of Enum type?
Typescript will not cast it for you in this case. You will need to typecast it yourself
type ColorType = 'red' | 'blue' | 'yellow';
type IJsonType = {"color" : ColorType}
let validJson = {
"color": "red" as ColorType
// or
// "color": "red" as const
}
let invalidJson = {
"color": "chartreuse"
}
const data1: IJsonType = validJson; // this MUST NOT error
const data2: IJsonType = invalidJson;
It's currently impossible in Typescript. There is an open issue/proposal for that: https://github.com/microsoft/TypeScript/issues/32063 (and a few similar ones).
The easiest way is to use as const
, but if you import json - then I'm not sure it's possible.
Also amakhrov
pointed to the current TS issue: https://github.com/microsoft/TypeScript/issues/32063
Until the issue has been fixed / implemented you can write a type assertion function to validate the type, check verifyColor
below. It takes an argument and asserts it's IJsonTypeWithEnum
.
// helps to detect flexible objects
export const isObject = (value: unknown): value is {[key in keyof any]: unknown} => {
return typeof value === 'object' && value !== null;
}
// solves issues with for key of
export const objectKeys = <T extends object, K extends keyof T>(value: T): Array<K> => {
return <Array<K>>Object.keys(value);
};
// THAT'S THE ANSWER
// verifies colors
const verifyColor = (value: unknown): value is IJsonTypeWithEnum => {
if (!isObject(value)) {
return false;
}
for (const key of objectKeys(ColorType)) {
if (ColorType[key] === value.color) {
return true;
}
}
return false;
};
const validJson: unknown = { "id": 3.14159 };
const invalidJson: unknown = { "id": "3.14159" };
const validJsonEnum: unknown = { "color": "red" };
const invalidJsonEnum: unknown = { "color": "chartreuse" };
enum ColorType {
red = 'red',
blue = 'blue',
yellow = 'yellow',
}
type IJsonType = {"id": number}
type IJsonTypeWithEnum = { "color": ColorType }
// asserting type
if (verifyColor(validJsonEnum)) { // add || 1 to check failure
const c: IJsonTypeWithEnum = validJsonEnum; // no error anymore
}
// asserting type
if (verifyColor(invalidJsonEnum)) { // add || 1 to check failure
const d: IJsonTypeWithEnum = invalidJsonEnum // no error anymore
}
Try to use type assertion
const data: IJsonType = jsonData as IJsonType;