如何在不修改类型与数据的前提下解决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
相关产品推荐
相关产品推荐

