Home > Blockchain >  How to dynamically create a typescript type from a static json schema that specifies types as string
How to dynamically create a typescript type from a static json schema that specifies types as string

Time:10-29

If I have a JSON schema saved in a file like f1040.json with content:

[
  {
    name: "L1",
    type: "String"
  },
  {
    name: "C2",
    type: "Boolean"
  },
  {
    name: "L3",
    type: "String"
  },
  ...
]

And I want to generate a type that looks like:

type F1040 = {
  L1: string;
  C2: boolean;
  L3: string;
  ...
}

How can I generate this without specifying each field manually (there are hundreds of them)? My first attempt at a solution isn't valid typescript (bc I'm providing more then one mapped type I think) but hopefully this invalid example clarifies what I'm trying to do:

import { f1040 } from "./f1040.json";

const bools = f1040.filter(e => e.type === "Boolean").map(e => name) as string[];
const strings = f1040.filter(e => e.type === "String").map(e => e.name) as string[];

export type F1040 = {
  [key in (typeof bools)[number]]?: boolean;
  [key in (typeof strings)[number]]?: string;
};

My incorrect solution was inspired by an answer to a similar but different question: TS create keys of new type from array of strings

Edit1: The solution doesn't need to be dynamic but if it's a build-time solution then it needs to play nice with rollup & the declarations bundler I'm using

Edit2: Another unsuccessful attempt, this time utilizing @sinclair/typebox:

import { Static, Type } from "@sinclair/typebox";

import { f1040 } from "./f1040.json";

const F1040 = Type.Object({
  ...f1040
    .filter(e => e.type === "Boolean")
    .map(e => e.name)
    .reduce((res, f) => ({ ...res, [f]: Type.Boolean() }), {}),
  ...f1040
    .filter(e => e.type === "String")
    .map(e => e.name)
    .reduce((res, f) => ({ ...res, [f]: Type.String() }), {}),
});
export type F1040 = Static<typeof F1040>;

const f1040Data = {
  L1: true,
  C2: "Yea",
} as F1040

The above attempt builds fine w/out any error.. which is too bad because the type assignments at the end are wrong. This should fail to build with a TypeError saying something like

Types of property 'L1' are incompatible. Type 'boolean' is not comparable to type 'string'.

CodePudding user response:

It cannot be done dynamically, because your typescipt program is compiled into javascript before it is run, and in javascript all type information is removed. Types are only used in the typescript compilation process.

So you need to have the types before typescript compilation. E.g. using https://www.npmjs.com/package/json-schema-to-typescript

  • Related