classFoo<Textendsstring|number>{constructor(publicprop: T){}method(){if(hasStringProp(this)){returnthis.prop.toUpperCase()// error! // Property 'toUpperCase' does not exist on type 'string | number'}if(hasNumberProp(this)){returnthis.prop.toFixed();// error! // Property 'prop' does not exist on type 'never'}thrownewError();}}functionhasStringProp(t: Foo<string|number>): t is Foo<string>{returntypeoft.prop==="string"}functionhasNumberProp(t: Foo<string|number>): t is Foo<number>{returntypeoft.prop==="number"}
π Actual behavior
Inside the respective blocks in method(), this is seen (via quickinfo) to have been narrowed to this & Foo<string> and then this & Foo<number>, and this.prop is seen to have been narrowed to T & string and then T & number. But actually trying to access this.prop as such produces errors about how this.prop is apparently string | number (as if no narrowing has occurred) in the first case, and how this is apparently never (as if too much narrowing has occurred) in the second case.
It really seems like the actual problem here is a hidden circularity. The return type of method() depends on the return type of hasStringProp(this) and hasNumberProp(this) which depends on Foo which depends on the method(). But no circularity warning is issued. Instead there's just these weird narrowing errors.
If you annotate the return type of method() explicitly, this problem goes away (starting with TS version 4.1.0-dev.20201028):
Bug Report
thistype guard, method, hidden circularity, annotated return type, user defined type guardPlayground link with relevant code
Inside the respective blocks in
method(),thisis seen (via quickinfo) to have been narrowed tothis & Foo<string>and thenthis & Foo<number>, andthis.propis seen to have been narrowed toT & stringand thenT & number. But actually trying to accessthis.propas such produces errors about howthis.propis apparentlystring | number(as if no narrowing has occurred) in the first case, and howthisis apparentlynever(as if too much narrowing has occurred) in the second case.It really seems like the actual problem here is a hidden circularity. The return type of
method()depends on the return type ofhasStringProp(this)andhasNumberProp(this)which depends onFoowhich depends on themethod(). But no circularity warning is issued. Instead there's just these weird narrowing errors.If you annotate the return type of
method()explicitly, this problem goes away (starting with TS version 4.1.0-dev.20201028):I'd expect either everything should just work, or if there's a circularity issue then it should be mentioned explicitly on
method().Comes from this Stack Overflow question
The text was updated successfully, but these errors were encountered: