You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从指定类型为字符串的静态JSON schema动态生成TypeScript类型

从JSON Schema批量生成F1040 TypeScript类型方案

错误原因说明

你之前的两种方案失效的核心问题一致:导入的JSON文件在TypeScript中默认会被推导为宽泛的Array<{name: string, type: string}>类型,丢失了字段名、字段类型的字面量信息,同时你手动加的as string[]断言进一步抹除了剩余的窄类型信息,最终生成的F1040类型是无字段校验能力的宽泛类型,自然不会触发类型错误。

你第一次写的映射类型语法错误,是因为TS不允许在同一个对象类型声明中写多个独立的in映射子句,需要用交叉类型拼接:

// 语法修复后的方案,前提是bools/strings有字面量类型
export type F1040 = 
  & { [key in typeof bools[number]]?: boolean }
  & { [key in typeof strings[number]]?: string }

可用方案

方案1:纯TS类型层实现(无额外依赖)

第一步先把f1040.json改为TS文件并加as const断言,保留字面量信息:

// f1040.ts
export default [
  { name: "L1", type: "String" },
  { name: "C2", type: "Boolean" },
  { name: "L3", type: "String" },
  // 其余字段
] as const

第二步写映射类型自动生成最终类型:

import f1040 from "./f1040";

type SchemaItem = typeof f1040[number]
// 映射JSON里的type到TS原生类型
type MapToTsType<T extends string> = 
  T extends "String" ? string :
  T extends "Boolean" ? boolean :
  never

// 自动生成带字段校验的类型
export type F1040 = {
  [Item in SchemaItem as Item['name']]: MapToTsType<Item['type']>
}

此时错误赋值会正常触发类型报错:

// 报错:类型“boolean”不能分配给类型“string”(L1字段)
const f1040Data: F1040 = {
  L1: true,
  C2: "Yea",
}

方案2:修复TypeBox实现

只需要给导入的schema加as const保留字面量类型即可:

import { Static, Type } from "@sinclair/typebox";
// 这里导入的f1040已经是加了as const的字面量类型
import f1040 from "./f1040";

const F1040Schema = Type.Object(
  Object.fromEntries(
    f1040.map(item => [
      item.name,
      item.type === "Boolean" ? Type.Boolean() : Type.String()
    ])
  )
);

export type F1040 = Static<typeof F1040Schema>;

// 此时错误赋值会正常触发校验
const f1040Data: F1040 = {
  L1: true,
  C2: "Yea",
}

方案3:构建时预生成d.ts(兼容现有rollup流程)

如果不想修改现有JSON结构,可以用Node脚本在构建前预生成静态声明文件,完全兼容你在用的声明打包器:

  1. 写生成脚本gen-f1040-type.js:
const fs = require('fs')
const f1040 = require('./f1040.json')

const typeFields = f1040.map(item => {
  const tsType = item.type === 'Boolean' ? 'boolean' : 'string'
  return `  ${item.name}: ${tsType};`
}).join('\n')

const dtsContent = `export type F1040 = {\n${typeFields}\n}`
fs.writeFileSync('./f1040.d.ts', dtsContent)
  1. 修改package.json的构建命令,在rollup打包前执行脚本:
{
  "scripts": {
    "prebuild": "node ./gen-f1040-type.js",
    "build": "rollup -c"
  }
}

生成的f1040.d.ts是静态类型文件,无任何运行时代码,和手动写的声明文件效果完全一致。


内容的提问来源于stack exchange,提问作者bohendo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 23:45:08