Cum să creezi dinamic un tip TypeScript dintr-un schemă JSON statică care specifică tipurile ca șiruri de caractere


Dacă am un schemă JSON salvată într-un fișier ca f1040.json cu conținut:

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

Și vreau să generez un tip care arată astfel:

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

Cum pot genera asta fără a specifica manual fiecare câmp (sunt sute de ele)? Prima mea încercare de soluție nu este TypeScript valabil (pentru că cred că ofer mai mult de un tip mapat), dar sper că acest exemplu nevalid clarifică ce încerc să fac:

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;
};

Soluția mea incorectă a fost inspirată de un răspuns la o întrebare similară, dar diferită: TS creează chei de tip nou dintr-un tablou de șiruri de caractere

Edit1: Soluția nu trebuie să fie dinamică, dar dacă este o soluție la timpul de construire, atunci trebuie să fie compatibilă cu rollup și cu generatorul de declarații pe care îl folosesc

Edit2: O altă încercare nereușită, de data aceasta folosind @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

Încercarea de mai sus se compilează bine fără nicio eroare... ceea ce este păcat pentru că atribuțiile de tip de la sfârșit sunt greșite. Aceasta ar trebui să eșueze la compilare cu o eroare de tip TypeError care să spună ceva de genul

Tipurile proprietății 'L1' sunt incompatibile. Tipul 'boolean' nu poate fi comparat cu tipul 'string'.

Răspuns #1

Nu se poate face dinamic, deoarece programul tău TypeScript este compilat în JavaScript înainte de a fi rulat, iar în JavaScript toate informațiile despre tipuri sunt eliminate. Tipurile sunt folosite doar în procesul de compilare TypeScript.

Așadar, trebuie să aveți tipurile înainte de compilarea TypeScript. De exemplu, folosind https://www.npmjs.com/package/json-schema-to-typescript