2

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'.

1
  • Do you have to do this dynamically? It would be trivial to write something that would take your JSON schema and write an interface or class definition in a .d.ts file... In fact I'm sure someone has already done it. Commented Oct 27, 2021 at 20:41

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

2 Comments

If I compile f1040.d.ts from a schema derived from f1040.json then how do I import the newly compiled type into an index.ts file in the same directory? The answer to this Q suggests that we need a file.ts alongside each file.d.ts but I'd rather not add a bunch of f1040.ts files for each form I'm using.
@bohendo No need for file.ts. You can do import { YourType] from './f1040'. Module resolution will add .d.ts. typescriptlang.org/docs/handbook/module-resolution.html

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.