我是TypeScript的新手,我面临一个非常琐碎的问题。我正在使用包装在我控制的服务功能中的第三方电子邮件库。第三方功能以及我的服务功能接受具有常见电子邮件配置属性(收件人,发件人,主题,正文等)的对象,但是第三方功能需要所有这些,而我的服务允许from属性是可选的。见下文。
// Third Party Code
type ThirdPartyEmailData = {
from: string;
to: string;
subject: string;
body: string;
}
const sendEmailWithThirdPartyService = (emailData: ThirdPartyEmailData) => {
console.log('Sending email from:', emailData);
}
-----------------------------------------------------------------------------
// My Code
type MyEmailData = {
from?: string;
to: string;
subject: string;
body: string;
}
const sendEmail = (emailData: MyEmailData) => {
emailData = { from: 'info@company.com', ...emailData };
sendEmailWithThirdPartyService(emailData); // This does not compile
/**
* Argument of type 'MyEmailData' is not assignable to parameter of type 'ThirdPartyEmailData'.
* Property 'from' is optional in type 'MyEmailData' but required in type 'ThirdPartyEmailData'.
*/
}
sendEmail({
to: 'john.doe@customer.com',
subject: 'I <3 TypeScript',
body: 'But TypeScript hates me'
});
按预期,由于无法将类型“ MyEmailData”分配给类型“ ThirdPartyEmailData”的参数,因此上述内容无法编译。我一直在寻找一种干净的方法来转换/更改/广播emailData的类型,然后再将其传递给第三方函数,但是我真的找不到一个好方法。以下是我想到的一些内容,但感觉不太好。
解决方案1:只需转换为第三方类型
// My Code
const sendEmail = (emailData: MyEmailData) => {
// If you remove the line below the program still compiles but breaks at runtime
emailData = { from: 'info@company.com', ...emailData };
sendEmailWithThirdPartyService(<ThirdPartyEmailData>emailData); // This compiles
}
解决方案2:使用类型保护以确保存在from属性
// My Code
const sendEmail = (emailData: MyEmailData) => {
emailData = { from: 'info@company.com', ...emailData };
// By using the type guard, we ensure that the type of emailData overlaps ThirdPartyEmailData
if (! hasFromProperty(emailData)) throw new Error('From property is missing');
sendEmailWithThirdPartyService(emailData); // This compiles
}
-----------------------------------------------------------------------------
// Utilities
/** Utility to make certain keys of a type required */
type RequiredKeys<T, K extends keyof T> = Exclude<T, K> & Required<Pick<T, K>>
/** Typeguard for property 'from' in MyEmailData */
const hasFromProperty = (data: MyEmailData): data is RequiredKeys<MyEmailData, 'from'> => {
return 'from' in data;
}
这似乎是一个非常普遍的问题,但我一直未能找到令人满意的解决方案。您能推荐什么?
答案 0 :(得分:1)
您应避免更改参数。就您而言,解决方案很简单:
const sendEmail = (emailData: MyEmailData) => {
const thirdPartyEmailData: ThirdPartyEmailData = { from: 'info@company.com', ...emailData };
sendEmailWithThirdPartyService(thirdPartyEmailData);
}
即使在不声明被推断出的ThirdPartyEmailData const thirdPartyEmailData = { from: 'info@company.com', ...emailData };
类型的情况下,它也可以正常工作。