Uh oh!
There was an error while loading. Please reload this page.
Fix #38608 - #38610
Fix #38608#38610
Conversation
Jack Williams (jack-williams)
commented
May 16, 2020
TypeScript Bot (@typescript-bot) test this |
Heya Jack Williams (@jack-williams), I've started to run the extended test suite on this PR at 2609521. You can monitor the build here. |
Heya Jack Williams (@jack-williams), I've started to run the parallelized community code test suite on this PR at 2609521. You can monitor the build here. |
TypeScript Bot (typescript-bot)
commented
May 16, 2020
The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master. |
Jack Williams (jack-williams)
commented
May 16, 2020
Baseline changes: VSCode fails on: functionimproveError(err: Error): Error{if('errno'inerr&&err['errno']==='ENOENT'&&'path'inerr&&typeoferr['path']==='string'){returnnewError(nls.localize('ext.term.app.not.found',"can't find terminal application '{0}'",err['path']));}returnerr;}Previously functionimproveError(err: Error&{errno?: unknown,path?: unknown}): Error{// ....Other diff looks unrelated. |
| function narrowByInKeyword(type: Type, literal: LiteralExpression, assumeTrue: boolean) { | ||
| if (type.flags & (TypeFlags.Union |TypeFlags.Object) || isThisTypeParameter(type)) { | ||
| if (type.flags & TypeFlags.Union || type.flags & TypeFlags.Object && declaredType.flags & TypeFlags.Union || isThisTypeParameter(type)) { |
There was a problem hiding this comment.
Rather than the declared type, shouldn't this just be looking at the input type? If we look at the declared type, it precludes things like
declarevarx: unknown;if(isAOrB(x)){if("aProp"inx){x;// A}elseif("bProp"inx){x;// B}elseif("cProp"inx){x;// never}}since I'm pretty sure we just merged a fix to a lot of cases like that.
There was a problem hiding this comment.
The fix that just went in was for discriminant property narrowing, which solved examples that are similar to yours, but it's a disjoint code path. Changing declaredType to type would revert to the original behaviour, but also have the correct behaviour here.
I've made a slight modification that narrows singletons if the current type is not the same as the declared type. This is abit of a hack, but in general working out the intent does not seem easy.
I added some discussion to the linked issue. The best thing might be to make no change at all.
Wesley Wigham (@weswigham) what do you think? should we take this or not? |
Wesley Wigham (weswigham)
left a comment
There was a problem hiding this comment.
Sure, this looks like both a pretty small change, and a pretty agreeable one now.
I'm happy to refresh this - just wondering whether to look into Anders' suggestion here? Maybe merge this and review that option later? |
Wesley Wigham (weswigham)
commented
Oct 28, 2020
🤷 I don't think we'll take this for the 4.1 RC this week, so there a few weeks you could experiment during until we're ready to start merging things for 4.2. |
Nathan Shively-Sanders (sandersn)
commented
Nov 2, 2020
Master is open for 4.2 PRs now. |
Wesley Wigham (weswigham)
commented
Nov 9, 2020
so Jack Williams (@jack-williams) you feel strongly one way or another with this now? |
…g-for-declared-singleton-case
Wesley Wigham (@weswigham) I merged master on this and opened another PR that tried the Perf looked ok - some changes in the binder but I think they are unrelated. My preference for There are some subtleties which arise because As it is now, the following behave the same (with and without my changes): typeAOrB={aProp: number}|{bProp: number};declarefunctionisAOrB(x: unknown): x is AOrB;declarevarx: unknown;declarevary: AOrB;if(isAOrB(x)){if("aProp"inx){x.aProp;}elseif("bProp"inx){x.bProp;}elseif("cProp"inx){const_never: never=x;}}if("aProp"iny){y.aProp;}elseif("bProp"iny){y.bProp;}elseif("cProp"iny){const_never: never=y;}But it is not the case that similar discrimant code behaves the same: typeA={kind: 'a'}typeB={kind: 'b'}typeAorB=A|B;declareconstx: unknown;declareconsty: AorB;declarefunctionisAorB(x: any): x is AorB;if(isAorB(x)){if(x.kind==="a"){}elseif(x.kind==="b"){x;}else{x// B;}}if(y.kind==="a"){}elseif(y.kind==="b"){}else{y;// never;}When you consider having declareconstw: AOrB;if("aProp"inw){w// A}elseif("bProp"inw){w// B}// w is never from hereelseif("cProp"inw){w}else{w}but check declareconstw: AOrB;if("aProp"inw){w// A}elseif("cProp"inw){w// w is { bProp: number } & Record<"cProp", unknown>}elseif("bProp"inw){w// B}else{w// never}
I think the second option is reasonable but I haven't been able to check user tests yet. |
Wesley Wigham (weswigham)
commented
Nov 10, 2020
Narrowing for |
Jack Williams (jack-williams)
commented
Nov 11, 2020
Would this be a way forward? The current PR is ready and the other PR (#41478) is nearly ready but needs some tests, to scan through the user tests, and to write up a description of the implemented behavior. I can do that work this week. At that point, it probably comes down to a discussion within the team to see if they want to consider moving forward with #41478, otherwise this can be merged. Merging this would not preclude #41478 at a later date, I think. In most cases this PR just changes some |
I agree, let's merge this one now. I'll add #41478 to the design meeting agenda. |
Fixes#38608
Narrowing an object to
neverusinginwhen the value was not declared as a union seems like undesirable behaviour.