TypeScript泛型约束问题:Unsafe assignment of an any value警告排查
问题描述
代码运行正常,但TypeScript对to: message.user.email,这行代码抛出Unsafe assignment of an any value警告,想排查原因。
相关代码:
发送邮件函数:
const sendWelcomeEmaill = async <T>(message: T) => { try { const result = await transporter.sendMail({ from: `"⚡ Magic NextAuth" ${env.EMAIL_FROM}`, to: message.user.email, subject: 'Welcome to Magic NextAuth! 🎉', html: `<div>HELLO</div>` } ); const failed = result.rejected.concat(result.pending).filter(Boolean); if (failed.length) { throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`); } } catch (error) { console.log(error); } }
函数调用场景(next-auth的events配置):
events: { createUser: async (message) => { await sendWelcomeEmail<typeof message>(message) // typeof message is equal to {user: User} }, },
问题原因
你给sendWelcomeEmail定义了泛型<T>,但没给这个泛型加任何类型约束,TypeScript没法推断出message里user和email属性的具体类型,所以把message.user.email判定为any类型,触发了不安全赋值的警告。
虽然调用时传了<typeof message>,但这个类型没有被TypeScript正确关联到函数内部的泛型T上,导致函数内部还是识别不了属性类型。
解决方案
方案1:给泛型添加类型约束
先定义和createUser事件参数匹配的类型,让TypeScript明确知道T的结构:
// 定义事件参数的类型结构 type CreateUserMessage = { user: { email: string; }; }; const sendWelcomeEmail = async <T extends CreateUserMessage>(message: T) => { try { const result = await transporter.sendMail({ from: `"⚡ Magic NextAuth" ${env.EMAIL_FROM}`, to: message.user.email, // 类型不再是any subject: 'Welcome to Magic NextAuth! 🎉', html: `<div>HELLO</div>` }); const failed = result.rejected.concat(result.pending).filter(Boolean); if (failed.length) { throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`); } } catch (error) { console.log(error); } }
方案2:直接使用具体类型代替泛型
既然你明确知道传入的是{user: User}类型,没必要用泛型,直接指定参数类型:
// 假设User类型已定义,包含email字段 const sendWelcomeEmail = async (message: { user: User }) => { try { const result = await transporter.sendMail({ from: `"⚡ Magic NextAuth" ${env.EMAIL_FROM}`, to: message.user.email, subject: 'Welcome to Magic NextAuth! 🎉', html: `<div>HELLO</div>` }); const failed = result.rejected.concat(result.pending).filter(Boolean); if (failed.length) { throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`); } } catch (error) { console.log(error); } }
方案3:使用next-auth内置的事件类型
next-auth已经为事件参数提供了内置类型,直接导入使用更准确:
import type { CreateUserEvent } from "next-auth/events"; const sendWelcomeEmail = async (message: CreateUserEvent) => { try { const result = await transporter.sendMail({ from: `"⚡ Magic NextAuth" ${env.EMAIL_FROM}`, to: message.user.email, subject: 'Welcome to Magic NextAuth! 🎉', html: `<div>HELLO</div>` }); const failed = result.rejected.concat(result.pending).filter(Boolean); if (failed.length) { throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`); } } catch (error) { console.log(error); } } // 调用时无需再传泛型 events: { createUser: async (message) => { await sendWelcomeEmail(message); }, },
内容的提问来源于stack exchange,提问作者John John
相关产品推荐
相关产品推荐

