如何避免JSON字符串转为TypeScript接口时出现多余未知属性
TypeScript 的静态类型(interface、type、类的类型声明)仅在编译时生效,运行时不会对实际的对象结构做任何校验或裁剪。JSON.parse方法返回的是无类型的任意对象,你给它加上Config类型标注只是编译层面的类型断言,并不会改变对象本身的内容,因此多余字段会完整保留。
以下是可落地的解决方案:
方案1:手动过滤+校验(无额外依赖)
直接编写逻辑只保留Config允许的字段,同时校验字段类型,不符合预期时抛出错误即可用try/catch捕获:
import * as fs from 'fs'; interface Config { port?: string, baud?: number, board?: string } // 定义允许的配置字段列表 const ALLOWED_CONFIG_FIELDS: Array<keyof Config> = ['port', 'baud', 'board']; function loadConfig(): Config { const rawConfig = JSON.parse(fs.readFileSync(`path/to/my/config.json`).toString()); if (typeof rawConfig !== 'object' || rawConfig === null) { throw new Error('配置文件格式错误,必须为JSON对象'); } const cleanedConfig: Config = {}; for (const key of ALLOWED_CONFIG_FIELDS) { if (key in rawConfig) { // 字段类型校验 if (key === 'baud' && typeof rawConfig[key] !== 'number') { throw new Error(`配置字段[baud]必须为数字类型`); } if ((key === 'port' || key === 'board') && typeof rawConfig[key] !== 'string') { throw new Error(`配置字段[${key}]必须为字符串类型`); } cleanedConfig[key] = rawConfig[key]; } } return cleanedConfig; } // 调用示例 let myConfig: Config; try { myConfig = loadConfig(); } catch (e) { // 配置异常处理逻辑,比如 fallback 到默认配置 console.error(`配置加载失败:${(e as Error).message},已使用默认配置`); myConfig = {}; }
该方案处理后得到的myConfig不会存在任何多余字段,适合配置结构简单的场景。
方案2:基于类的构造校验
如果需要更封装的处理,可以将校验逻辑写到类的构造函数中:
import * as fs from 'fs'; class Config { port?: string; baud?: number; board?: string; constructor(raw: unknown) { if (typeof raw !== 'object' || raw === null) { throw new Error('配置必须为JSON对象'); } const rawObj = raw as Record<string, unknown>; if ('port' in rawObj) { if (typeof rawObj.port !== 'string') throw new Error('port必须为字符串'); this.port = rawObj.port; } if ('baud' in rawObj) { if (typeof rawObj.baud !== 'number') throw new Error('baud必须为数字'); this.baud = rawObj.baud; } if ('board' in rawObj) { if (typeof rawObj.board !== 'string') throw new Error('board必须为字符串'); this.board = rawObj.board; } } } // 调用示例 try { const raw = JSON.parse(fs.readFileSync(`path/to/my/config.json`).toString()); const myConfig = new Config(raw); } catch (e) { // 异常处理逻辑 }
方案3:运行时校验库(适合复杂配置场景)
如果配置结构复杂、不想手动编写大量校验逻辑,可以使用Zod这类运行时类型校验库,既能自动校验结构、过滤多余字段,也能直接生成对应的TS类型:
import * as fs from 'fs'; import { z } from 'zod'; // 定义运行时校验规则 const ConfigSchema = z.object({ port: z.string().optional(), baud: z.number().optional(), board: z.string().optional() // .strict() // 开启后遇到多余字段会直接抛错,不开启则自动过滤多余字段 }); // 自动生成TS类型 type Config = z.infer<typeof ConfigSchema>; // 调用示例 try { const raw = JSON.parse(fs.readFileSync(`path/to/my/config.json`).toString()); const myConfig = ConfigSchema.parse(raw); } catch (e) { // 校验失败异常处理 }
内容的提问来源于stack exchange,提问作者Ratibus11
相关产品推荐
相关产品推荐

