【问题标题】:How to dynamically create a typescript type from a static json schema that specifies types as strings如何从将类型指定为字符串的静态 json 模式动态创建打字稿类型
【发布时间】:2021-12-13 03:07:21
【问题描述】:

如果我将 JSON 模式保存在像 f1040.json 这样的文件中,内容如下:

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

我想生成一个看起来像这样的类型:

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

如何在不手动指定每个字段的情况下生成此字段(有数百个字段)?我对解决方案的第一次尝试不是有效的打字稿(我认为我提供的映射类型不止一个),但希望这个无效的示例能够阐明我正在尝试做的事情:

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

我不正确的解决方案的灵感来自一个类似但不同的问题的答案:TS create keys of new type from array of strings

Edit1:解决方案不需要是动态的,但如果它是构建时解决方案,那么它需要与 rollup 和 declarations bundler I'm using 配合得很好

Edit2:另一个不成功的尝试,这次使用@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

上面的尝试构建得很好,没有任何错误。这太糟糕了,因为最后的类型分配是错误的。这应该无法使用 TypeError 来构建,比如

属性“L1”的类型不兼容。 'boolean' 类型与 'string' 类型不可比较。

【问题讨论】:

  • 您必须动态执行此操作吗?编写一些将您的 JSON 模式并在 .d.ts 文件中写入 interfaceclass 定义的东西是微不足道的......事实上我确信有人已经这样做了。

标签: json typescript


【解决方案1】:

它不能动态完成,因为你的 typecipt 程序在运行之前被编译成 javascript,并且在 javascript 中所有类型信息都被删除了。类型只在 typescript 编译过程中使用。

所以你需要在 typescript 编译之前有类型。例如。使用https://www.npmjs.com/package/json-schema-to-typescript

【讨论】:

  • 如果我从派生自f1040.json 的架构编译f1040.d.ts,那么如何将新编译的类型导入同一目录中的index.ts 文件? this Q 的答案表明我们需要在每个 file.d.ts 旁边添加一个 file.ts,但我不想为我正在使用的每个表单添加一堆 f1040.ts 文件。
  • @bohendo 不需要file.ts。你可以做import { YourType] from './f1040'。模块分辨率将添加.d.tstypescriptlang.org/docs/handbook/module-resolution.html
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-23
  • 2022-12-19
  • 2020-03-24
  • 2021-08-13
  • 2020-04-02
  • 2020-03-09
相关资源
最近更新 更多