GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — nullish coalescing commit by Kingwl · Pull Request #32883 · microsoft/TypeScript Conversation
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Is this the real life? 😍 |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
TypeScript Bot (@typescript-bot) test this. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Heya Wenlu Wang (@Kingwl), I've started to run the extended test suite on this PR at 2327b3b. You can monitor the build here. It should now contribute to this PR's status checks. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| leftType; | ||
| case SyntaxKind.QuestionQuestionToken: | ||
| return getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ? | ||
| getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) : |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to also return a union type for when strictNullChecks is off?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I'd like to say yes, every value could be null/undefined if strictNullChecks is off and we cannot detect that.
same as:
declare const a: string let b = a || 1 // b is string || number
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| return createBinary(left, SyntaxKind.BarBarToken, right); | ||
| } | ||
|
|
||
| export function createNullishCoalescing(left: Expression, right: Expression) { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Nit: createNullishCoalesce? I dunno, what do you think Ron Buckton (@rbuckton)?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Progress looks great!
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
|
||
| //// [nullishCoalescingOperator1.js] | ||
| "use strict"; | ||
| var aa1 = typeof a1 !== "undefined" && a1 !== null ? a1 : 'whatever'; |
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Just as a heads up, we might want to just go with a1 != null, since document.all is a weird anomaly of the language anyway that should ideally never be used in a ?? expression.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Daniel Rosenwasser (@DanielRosenwasser)
Sorry for the late comment after TypeScript 3.7 release.
But what about the shorter implementation of ?? operator that you have suggested?
This implementation with less code is better for all of us, I think.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
declare let a: any, b: any, c: any; let x1 = (a ?? b as any) || c; let x2 = c || (a ?? b as any); let x3 = ((a ?? b) as any) || c; let x4 = c || ((a ?? b) as any); let x5 = (a ?? b) as any || c; let x6 = c || (a ?? b) as any; let y1 = (a ?? b as any) && c; let y2 = c && (a ?? b as any); let y3 = ((a ?? b) as any) && c; let y4 = c && ((a ?? b) as any); let y5 = (a ?? b) as any && c; let y6 = c && (a ?? b) as any; |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
… grammar restrictions when assertions are used.
…red). Added tests to ensure calls and property accesses are only called once.
…wl/TypeScript into nullish-coalescing-operator
|
Daniel Rosenwasser (@DanielRosenwasser) I've added the tests, emit appears to work as expected keeping the
Hope I didn't miss the point of the tests 😅 Ron Buckton (@rbuckton) or Daniel Rosenwasser (@DanielRosenwasser) But if //test2.ts let x = { y: 1, x: 0 } let v = 0; Object.defineProperty(x, "x", { get() { return v++; } }) export = x; //usage.ts import { x, y } from './test2' let xo = x ?? "NO" console.log(xo); let yo = y ?? "NO" console.log(yo); This will output I would just use the approach babel uses, use a temporary variable always ex. Thoughts ? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I think "use a temporary unless it's an identifier" is usually the approach we take. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Daniel Rosenwasser (@DanielRosenwasser) Mkay 😕, so ignore the corner case above ? Just to make sure I was clear in what I was trying to say |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Nullish coalescing operator
There was an error while loading. Please reload this page.
|
Titian Cernicova-Dragomir (@dragomirtitian)
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
TypeScript Bot (@typescript-bot) pack this. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Heya Wenlu Wang (@Kingwl), I've started to run the tarball bundle task on this PR at 57be95d. You can monitor the build here. It should now contribute to this PR's status checks. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Hey Wenlu Wang (@Kingwl), I've packed this into an installable tgz. You can install it for testing by referencing it in your and then running |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| @@ -1502,6 +1503,7 @@ namespace ts { | |||
| export type LogicalOperator | |||
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
This is actually kind of strange because it's not really a LogicalOperator. Should it be moved out?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Would you be able to update the API baselines?
We'd really like to merge this in by tomorrow for the beta. There seem to be only minor issues (control flow analysis not being entirely correct), but those can be fixed by the RC.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| } | ||
|
|
||
| function createNotNullCondition(node: Expression) { | ||
| return createBinary( |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Since optional chaining uses strict equality, can you switch this to strict equality?
createBinary( createBinary( temp createToken(SyntaxKind.ExclamationEqualsEqualsToken), createNull() ), createToken(SyntaxKind.AmpersandAmpersandToken), createBinary( temp, createToken(SyntaxKind.ExclamationEqualsEqualsToken), createVoidZero() ) );
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| (<BinaryExpression>node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || | ||
| (<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken); | ||
| (<BinaryExpression>node).operatorToken.kind === SyntaxKind.BarBarToken || | ||
| (<BinaryExpression>node).operatorToken.kind === SyntaxKind.QuestionQuestionToken); |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
?? isn't really a logical operator. This results in control-flow treating the branch as something "truthy" not something defined/undefined.
I'd like to see some tests for control flow.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I’ll update that today |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…cript into nullish-coalescing-operator
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Some trivial things.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| bindCondition(node.right, trueTarget, falseTarget); | ||
| } | ||
|
|
||
| function bindNullishCollasingExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Typo: bindNullishCollasingExpression -> bindNullishCoalescingExpression
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| function bindBinaryExpressionFlow(node: BinaryExpression) { | ||
| const operator = node.operatorToken.kind; | ||
| if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) { | ||
| if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Nit: This if-chain would be easier to read as a switch
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I prefer to keep this because of so many other code similar to that.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| pos++; | ||
| return token = SyntaxKind.GreaterThanToken; | ||
| case CharacterCodes.question: | ||
| if (text.charCodeAt(pos + 1) === CharacterCodes.question) { |
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Nit: If you re-order the pos++ before the if, the code become marginally simpler.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I prefer to be consistent with the existed code.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
# Conflicts: # src/compiler/scanner.ts # src/compiler/transformers/esnext.ts # src/compiler/utilities.ts # tests/baselines/reference/api/tsserverlibrary.d.ts # tests/baselines/reference/api/typescript.d.ts
|
Wenlu Wang (@Kingwl): Thanks for the contribution! My changes were mostly to merge the control-flow behavior of nullish-coalesce with the control-flow behavior of optional chaining and to resolve merge conflicts so that this could be merged with master for the 3.7 beta. Thanks again for all of the hard work! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thank you all for your hard work on this and congrats on the 3.7 release! I have a small question out of curiosity. For let x = (foo !== null && foo !== undefined) ? foo : bar; // vs let x = foo != null ? foo : bar; |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Nullish coalescing operator (??)
There was an error while loading. Please reload this page.