Skip to content

Instantly share code, notes, and snippets.

@gfx
Last active November 22, 2020 12:32
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save gfx/7a35efaca5e6b40a8b4f888b7f36a5d1 to your computer and use it in GitHub Desktop.
Type-Function to Parse JSON into TypeScript types
type Whitespace = " " | "\n" | "\r" | "\t";
type TrimStart<T extends string> = T extends `${Whitespace}${infer R}` ? TrimStart<R> : T;
type TrimEnd<T extends string> = T extends `${infer R}${Whitespace}` ? TrimEnd<R> : T;
type Trim<T extends string> = TrimStart<TrimEnd<T>>;
type BoolLiteral = "true" | "false";
type Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9";
type InferJsonScalarType<T extends string> = Trim<T> extends `"${infer _}"` ? string
: Trim<T> extends `${BoolLiteral}` ? boolean
: Trim<T> extends `${Digit}${infer _}` ? number
: Trim<T> extends `null` ? null
: never;
type HeadingJsonScalar<T extends string> = Trim<T> extends `"${infer Str}",${infer _}` ? `"${Str}"`
: Trim<T> extends `${infer Token},${infer _}` ? Token
: T;
type TrailingJsonEntries<T extends string> = Trim<T> extends `"${infer _}",${infer Tail}` ? Tail
: Trim<T> extends `${infer _},${infer Tail}` ? Tail
: T;
type DecodeJsonStr<T extends string> = T extends `"${infer R}"` ? R : never;
type InfoerJsonObjectEntries<T extends string> = Trim<T> extends `${infer K}:${infer Tail}`
? { [key in DecodeJsonStr<Trim<K>>]: InferJsonScalarType<HeadingJsonScalar<Tail>> } & InfoerJsonObjectEntries<TrailingJsonEntries<Tail>>
: {};
export type TypeFromJson<T extends string> = Trim<T> extends `{${infer InnerJsonObject}}`
? InfoerJsonObjectEntries<InnerJsonObject>
: never;
const json = `
{
"name": "foo",
"answer": 42,
"ok": true
}
`;
type ResultType = TypeFromJson<typeof json>;
// ResultType is almost { name: string; answer: number; ok: boolean }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment