TypeScript中类型守卫返回值为何写`this is (…) & this`?能否省略?
TypeScript类中this类型守卫的疑问:为何无需显式
& this? 我在阅读TypeScript手册的《类》章节时,对两个类型守卫示例的差异感到困惑:
- 示例1中,类型守卫的返回类型显式写为
this is Networked & this,这部分我能理解。 - 示例2中仅写
this is { value: T },但if代码块中box的类型却是Box<string> & { value: string; }。
按照第一个示例的逻辑,我认为应该写成this is { value: T } & this才对,这是否意味着我总能省略显式的& this?
示例1
class FileSystemObject { isFile(): this is FileRep { return this instanceof FileRep; } isDirectory(): this is Directory { return this instanceof Directory; } isNetworked(): this is Networked & this { // 此处显式写了& this return this.networked; } constructor(public path: string, private networked: boolean) {} } class FileRep extends FileSystemObject { constructor(path: string, public content: string) { super(path, false); } } class Directory extends FileSystemObject { children: FileSystemObject[]; } interface Networked { // 独立接口,与FileSystemObject无继承关系 host: string; } const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo"); if (fso.isFile()) { fso.content; } else if (fso.isDirectory()) { fso.children; } else if (fso.isNetworked()) { fso.host; // 类型为Networked & FileSystemObject }
示例2
class Box<T> { value?: T; hasValue(): this is { value: T } { // 此处未写& this return this.value !== undefined; } } const box = new Box<string>(); box.value = "Gameboy"; if (box.hasValue()) { box.value; // 类型为Box<string> & { value: string; } }
核心原因:TypeScript的自动类型合并逻辑
当你在类的方法中使用this is X作为类型守卫的返回类型时,TypeScript会自动将当前的this类型与X进行交叉合并,不需要你显式添加& this。
示例1显式写& this的原因
示例1中的Networked是一个完全独立的接口,和FileSystemObject类没有继承或实现关系。早期TypeScript版本中,这类跨类型的守卫可能无法自动完成合并,所以手册里用显式的& this来明确展示最终的交叉类型效果。不过在当前新版本的TypeScript中,即使省略& this,类型推导也能正常工作,手册保留这种写法更多是为了教学上的清晰性。
示例2无需显式写的原因
示例2中的{ value: T }是对Box<T>原有类型的补充——原类里value是可选属性,类型守卫的作用只是将其转为必填。这种场景下,TypeScript会自动把this的原始类型(Box<T>)和守卫目标类型({ value: T })交叉,所以if代码块里的box自然会被推导为Box<string> & { value: string; }。
总结
- 绝大多数场景下,你完全可以省略显式的
& this,TypeScript会自动处理类型合并。 - 只有当你需要明确展示合并后的类型结构,或者遇到极少数老版本/复杂推导的边缘场景时,才需要手动添加
& this,但这不是必须的。
内容的提问来源于stack exchange,提问作者NeoZoom.lua
相关产品推荐
相关产品推荐

