TypeScript中if语句判断对象属性时的类型推断异常问题
TypeScript类型收窄的局限:交叉类型场景下的类型匹配问题
先看你的代码场景:
export type IssueProps = { type: 'job_warning' | 'job_error' | 'task_warning' jobId?: string } export type JobIssueProps = IssueProps & { type: 'job_warning' | 'job_error' jobId: string } const sendDeadlineJobErrorAlert = (deadlineIssue: JobIssueProps) => { console.log(deadlineIssue) } const issue = {} as IssueProps if (issue.type === 'job_error' && issue.jobId) { // TypeScript报错 sendDeadlineJobErrorAlert(issue) } if (issue.type === 'job_error' && issue.jobId) { // 无报错 sendDeadlineJobErrorAlert({...issue, type: issue.type, jobId: issue.jobId}) }
报错信息:
Argument of type 'IssueProps' is not assignable to parameter of type 'JobIssueProps'. Type 'IssueProps' is not assignable to type '{ type: "job_warning" | "job_error"; jobId: string; }'. Types of property 'type' are incompatible. Type '"job_warning" | "job_error" | "task_warning"' is not assignable to type '"job_warning" | "job_error"'. Type '"task_warning"' is not assignable to type '"job_warning" | "job_error"'.
为什么第一个if报错,第二个不报错?
这不是你的写法错误,而是TypeScript类型系统在处理交叉类型与原类型的收窄映射时的局限:
第一个if的问题:
虽然你通过issue.type === 'job_error'收窄了type的取值范围,又通过issue.jobId确认了该属性存在,但TypeScript无法将IssueProps这个宽泛类型,自动推导为JobIssueProps这个交叉类型。
原因在于:JobIssueProps是IssueProps与另一个类型的交叉,TS的内置类型守卫(比如属性检查、字面量判断)只能收窄对象的单个属性类型,无法自动将整个对象的类型转换为交叉后的复合类型——它仍然认为issue的基础类型是IssueProps,而这个类型的type仍然包含task_warning的可能(即使你已经通过判断排除了)。第二个if的正常逻辑:
当你创建{...issue, type: issue.type, jobId: issue.jobId}这个新对象时,TypeScript会重新推断这个新对象的类型:type此时已经被收窄为'job_error',符合JobIssueProps的type要求;jobId被确认是存在的字符串,符合必填要求;
所以这个新对象的类型会被自动推断为完全匹配JobIssueProps,自然不会报错。
解决方案
如果不想创建新对象,可以通过类型断言或者自定义类型守卫来解决:
方案1:类型断言
if (issue.type === 'job_error' && issue.jobId) { sendDeadlineJobErrorAlert(issue as JobIssueProps) }
方案2:自定义类型守卫
function isJobIssueProps(issue: IssueProps): issue is JobIssueProps { return (issue.type === 'job_warning' || issue.type === 'job_error') && !!issue.jobId } if (isJobIssueProps(issue) && issue.type === 'job_error') { sendDeadlineJobErrorAlert(issue) }
内容的提问来源于stack exchange,提问作者Noname
相关产品推荐
相关产品推荐

