- Notifications
You must be signed in to change notification settings - Fork12.9k
nullish coalescing commit#32883
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
nullish coalescing commit#32883
Uh oh!
There was an error while loading.Please reload this page.
Conversation
b33eeac
to2ef3e0f
CompareIs this the real life? 😍 |
@typescript-bot test this. |
typescript-bot commentedAug 15, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
src/compiler/checker.ts Outdated
@@ -23917,6 +23918,10 @@ namespace ts { | |||
return getTypeFacts(leftType) & TypeFacts.Falsy ? | |||
getUnionType([removeDefinitelyFalsyTypes(leftType), rightType], UnionReduction.Subtype) : | |||
leftType; | |||
case SyntaxKind.QuestionQuestionToken: | |||
return getTypeFacts(leftType) & TypeFacts.EQUndefinedOrNull ? | |||
getUnionType([getNonNullableType(leftType), rightType], UnionReduction.Subtype) : |
There was a problem hiding this comment.
Choose a reason for 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 whenstrictNullChecks
is off?
There was a problem hiding this comment.
Choose a reason for 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:
declareconsta:stringletb=a||1// b is string || number
src/compiler/factory.ts Outdated
@@ -3044,6 +3044,10 @@ namespace ts { | |||
return createBinary(left, SyntaxKind.BarBarToken, right); | |||
} | |||
export function createNullishCoalescing(left: Expression, right: Expression) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Nit:createNullishCoalesce
? I dunno, what do you think@rbuckton?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Progress looks great!
//// [nullishCoalescingOperator1.js] | ||
"use strict"; | ||
var aa1 = typeof a1 !== "undefined" && a1 !== null ? a1 : 'whatever'; |
DanielRosenwasserAug 15, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for 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 witha1 != null
, sincedocument.all
is a weird anomaly of the language anyway that should ideally never be used in a??
expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
@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.
DanielRosenwasser commentedAug 15, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
declareleta:any,b:any,c:any;letx1=(a??basany)||c;letx2=c||(a??basany);letx3=((a??b)asany)||c;letx4=c||((a??b)asany);letx5=(a??b)asany||c;letx6=c||(a??b)asany;lety1=(a??basany)&&c;lety2=c&&(a??basany);lety3=((a??b)asany)&&c;lety4=c&&((a??b)asany);lety5=(a??b)asany&&c;lety6=c&&(a??b)asany; |
… 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
@DanielRosenwasser I've added the tests, emit appears to work as expected keeping the
Hope I didn't miss the point of the tests 😅 @rbuckton or@DanielRosenwasser But if //test2.tsletx={y:1,x:0}letv=0;Object.defineProperty(x,"x",{get(){returnv++;}})export=x;//usage.tsimport{x,y}from'./test2'letxo=x??"NO"console.log(xo);letyo=y??"NO"console.log(yo); This will output I would just use the approach babel uses, use a temporary variable alwaysex. Thoughts ? |
I think "use a temporary unless it's an identifier" is usually the approach we take. |
@DanielRosenwasser Mkay 😕, so ignore the corner case above ? Just to make sure I was clear in what I was trying to say |
Nullish coalescing operator
Kingwl commentedAug 16, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@dragomirtitian
|
@typescript-bot pack this. |
typescript-bot commentedSep 20, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Hey@Kingwl, I've packed this intoan installable tgz. You can install it for testing by referencing it in your
and then running |
src/compiler/types.ts Outdated
@@ -1502,6 +1503,7 @@ namespace ts { | |||
export type LogicalOperator |
There was a problem hiding this comment.
Choose a reason for 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 notreally a LogicalOperator. Should it be moved out?
DanielRosenwasser left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for 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.
default: | ||
return visitEachChild(node, visitor, context); | ||
} | ||
} | ||
function createNotNullCondition(node: Expression) { | ||
return createBinary( |
There was a problem hiding this comment.
Choose a reason for 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(tempcreateToken(SyntaxKind.ExclamationEqualsEqualsToken),createNull()),createToken(SyntaxKind.AmpersandAmpersandToken),createBinary(temp,createToken(SyntaxKind.ExclamationEqualsEqualsToken),createVoidZero()));
@@ -943,7 +943,8 @@ namespace ts { | |||
else { | |||
return node.kind === SyntaxKind.BinaryExpression && ( | |||
(<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.
Choose a reason for 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.
I’ll update that today |
Uh oh!
There was an error while loading.Please reload this page.
robpalme left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Some trivial things.
src/compiler/binder.ts Outdated
@@ -1435,6 +1435,14 @@ namespace ts { | |||
bindCondition(node.right, trueTarget, falseTarget); | |||
} | |||
function bindNullishCollasingExpression(node: BinaryExpression, trueTarget: FlowLabel, falseTarget: FlowLabel) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Typo:bindNullishCollasingExpression
->bindNullishCoalescingExpression
@@ -1461,12 +1469,15 @@ namespace ts { | |||
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.
Choose a reason for 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 aswitch
There was a problem hiding this comment.
Choose a reason for 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.
src/compiler/scanner.ts Outdated
@@ -1828,6 +1831,9 @@ namespace ts { | |||
pos++; | |||
return token = SyntaxKind.GreaterThanToken; | |||
case CharacterCodes.question: | |||
if (text.charCodeAt(pos + 1) === CharacterCodes.question) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Nit: If you re-order thepos++
before theif
, the code become marginally simpler.
There was a problem hiding this comment.
Choose a reason for 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.
# 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
@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! |
wsmd commentedNov 6, 2019
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 letx=(foo!==null&&foo!==undefined) ?foo :bar;// vsletx=foo!=null ?foo :bar; |
|
Uh oh!
There was an error while loading.Please reload this page.
followhttps://tc39.es/proposal-nullish-coalescing/
Fixes#26578
TODO: