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

如何避免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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:24:00