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

TypeScript如何根据传入对象类型选择对应属性实现通用解析函数

TypeScript 联合类型对象通用解析方案

问题描述

现有两种不同结构的话题对象类型,分别对应不同数据源的字段命名规则,需要实现通用的parseTopic函数,自动识别传入对象的结构、提取对应字段值完成解析。直接访问联合类型的独有属性时,TypeScript会抛出类型错误,提示属性不存在于联合类型的另一成员上。
原始问题代码如下:

enum FirstSourceTopicAliases {
    Topic = 'topic',
    TopicText = 'topic_text',
    TopicLink = 'topic_link',
}
enum SecondSourceTopicAliases {
    Topic = 'title',
    TopicText = 'body',
    TopicLink = 'link',
}
interface FirstSourceTopic {
    [FirstSourceTopicAliases.Topic]: string,
    [FirstSourceTopicAliases.TopicText]: string,
    [FirstSourceTopicAliases.TopicLink]: string,
}
interface SecondSourceTopic {
    [SecondSourceTopicAliases.Topic]: string,
    [SecondSourceTopicAliases.TopicText]: string,
    [SecondSourceTopicAliases.TopicLink]: string,
}

type Topic = FirstSourceTopic | SecondSourceTopic

const parseTopic = (topic: Topic) => {
    const parsedTopic = {
        topic: 'parsed' + topic.topic // 或 topic.title,直接写会报TS错误
        topicText: 'parsed' + topic.topic_text // 或 topic.body,直接写会报TS错误
        topicLink: 'parsed' + topic.topic_link, // 或 topic.link,直接写会报TS错误
    }

    return parsedTopic
}

const firstSourceTopic: FirstSourceTopic = {
    topic: 'some topic',
    topic_text: 'some topic text',
    topic_link: 'some topic link',
}
const secondSourceTopic: SecondSourceTopic = {
    title: 'some topic',
    body: 'some topic text',
    link: 'some topic link',
}

const parsedTopic = parseTopic(firstSourceTopic)
console.log(parsedTopic)

实现方案

核心思路是统一维护语义字段和各数据源别名的映射关系,通过in操作符做类型守卫自动识别当前对象存在的字段,不需要零散硬编码类型判断,后续扩展新的数据源也只需要修改映射配置,不需要改动核心解析逻辑。
改造后的完整代码:

enum FirstSourceTopicAliases {
    Topic = 'topic',
    TopicText = 'topic_text',
    TopicLink = 'topic_link',
}
enum SecondSourceTopicAliases {
    Topic = 'title',
    TopicText = 'body',
    TopicLink = 'link',
}
interface FirstSourceTopic {
    [FirstSourceTopicAliases.Topic]: string,
    [FirstSourceTopicAliases.TopicText]: string,
    [FirstSourceTopicAliases.TopicLink]: string,
}
interface SecondSourceTopic {
    [SecondSourceTopicAliases.Topic]: string,
    [SecondSourceTopicAliases.TopicText]: string,
    [SecondSourceTopicAliases.TopicLink]: string,
}

type Topic = FirstSourceTopic | SecondSourceTopic

// 统一维护语义字段对应的所有数据源别名
const FIELD_ALIAS_MAP = {
    topic: [FirstSourceTopicAliases.Topic, SecondSourceTopicAliases.Topic],
    topicText: [FirstSourceTopicAliases.TopicText, SecondSourceTopicAliases.TopicText],
    topicLink: [FirstSourceTopicAliases.TopicLink, SecondSourceTopicAliases.TopicLink]
} as const;

/**
 * 通用字段取值函数:自动匹配当前topic对象存在的别名字段取值
 */
const getFieldValue = (topic: Topic, semanticField: keyof typeof FIELD_ALIAS_MAP): string => {
    const aliases = FIELD_ALIAS_MAP[semanticField];
    for (const alias of aliases) {
        // in 操作符是TS原生支持的类型守卫,可自动缩窄对象类型
        if (alias in topic) {
            return topic[alias];
        }
    }
    throw new Error(`Invalid topic structure: missing required field ${semanticField}`);
}

const parseTopic = (topic: Topic) => {
    return {
        topic: 'parsed ' + getFieldValue(topic, 'topic'),
        topicText: 'parsed ' + getFieldValue(topic, 'topicText'),
        topicLink: 'parsed ' + getFieldValue(topic, 'topicLink')
    }
}

// 测试用例
const firstSourceTopic: FirstSourceTopic = {
    topic: 'some topic',
    topic_text: 'some topic text',
    topic_link: 'some topic link',
}
const secondSourceTopic: SecondSourceTopic = {
    title: 'some topic',
    body: 'some topic text',
    link: 'some topic link',
}

console.log(parseTopic(firstSourceTopic))
// 输出:{ topic: 'parsed some topic', topicText: 'parsed some topic text', topicLink: 'parsed some topic link' }
console.log(parseTopic(secondSourceTopic))
// 输出:{ topic: 'parsed some topic', topicText: 'parsed some topic text', topicLink: 'parsed some topic link' }

方案优势

  • 完全通过TS类型检查,不会出现联合类型属性访问报错
  • 解析逻辑和字段映射解耦,后续新增其他数据源的Topic类型,只需要新增对应别名枚举、补充映射配置即可,不需要修改parseTopic核心逻辑
  • 容错性强,遇到结构不符合要求的对象会抛出明确的错误信息,方便排查问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:06:28