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

如何在不修改类型与数据的前提下解决TypeScript类型错误?

问题:TypeScript类型错误解决(不修改类型定义与原始数据)

我正在编写一个合并两组API返回数据的程序,需要处理数据未定义的情况。但在执行item.id === message.sender.userId时,userId出现类型错误。希望在不修改类型定义与原始数据的前提下解决这个问题,是否可行?

相关代码与数据:

const newMessages = React.useMemo(() => {
  if (messages === undefined || userItems === undefined) return [];
  return messages.map(message => {
    if (message.sender.type === "user" && message.sender.userId) {
      const user = userItems.find(item => item.id === message.sender.userId);
      if (user) message.sender = { ...message.sender, icon: user.image };
    }
    return message;
  });
}, [messages, userItems]);

类型定义与示例数据:

type IMessage = {
  sender:
    | {
        type: "user";
        userId: number;
      }
    | {
        type: "admin";
        adminId: number;
      };
  body:
    | {
        type: "text";
        text: "text";
      }
    | {
        type: "image";
        text: string;
        image: string;
      };
};


const messages: IMessage[] =
[
    {
        "sender": {
            "type": "admin",
            "adminId": 789
        },
        "body": {
            "type": "image",
            "text": "abcde",
            "image": "https://imageUrl"
        },
    },
    {
        "sender": {
            "type": "user",
            "userId": 10
        },
        "body": {
            "type": "text",
            "text": "Hello!"
        },
    },
    {
        "sender": {
            "type": "user",
            "userId": 13
        },
        "body": {
            "type": "image",
            "text": "Hello my friend!",
            "image": "https://imageUrl"
        },
    },
]

const userItems =
[
    {
        "id": 10,
        "name": "kenny",
        "image": "https://imageUrl",
        "age": 23,
        "gender": "M",
    },
    {
        "id": 13,
        "name": "Jon",
        "image": "https://imageUrl",
        "age": 32,
        "gender": "M",
    }
]

解决方案

可行,以下两种方式都能在不修改原类型定义和数据的前提下解决问题:

方法1:类型守卫+类型断言

通过message.sender.type === "user"已经做了类型区分,但TS有时会因为逻辑嵌套导致类型收窄不彻底,手动添加类型断言明确类型即可:

const newMessages = React.useMemo(() => {
  if (messages === undefined || userItems === undefined) return [];
  return messages.map(message => {
    if (message.sender.type === "user") {
      // 断言为user类型的sender
      const userSender = message.sender as { type: "user"; userId: number };
      const user = userItems.find(item => item.id === userSender.userId);
      if (user) {
        // 返回新对象避免修改原数据(可选但推荐)
        return {
          ...message,
          sender: { ...userSender, icon: user.image }
        };
      }
    }
    return message;
  });
}, [messages, userItems]);

方法2:非空断言(需确保userId必存在)

如果你能保证所有type: "user"的sender都有userId(从示例数据看符合),可以直接给userId加非空断言!,告诉TS这个值一定不为空:

const newMessages = React.useMemo(() => {
  if (messages === undefined || userItems === undefined) return [];
  return messages.map(message => {
    if (message.sender.type === "user") {
      const user = userItems.find(item => item.id === message.sender.userId!);
      if (user) {
        return {
          ...message,
          sender: { ...message.sender, icon: user.image }
        };
      }
    }
    return message;
  });
}, [messages, userItems]);

额外提示

原代码中直接修改message.sender对象,虽然能运行,但如果原数据是不可变状态(比如Redux、React状态),可能引发意外问题,建议返回新的message对象而非修改原数据,上面的示例已经做了优化。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:30:54