From b33eeac4864bb0e8be2e2fc537e0ff853fcfac62 Mon Sep 17 00:00:00 2001 From: kingwl Date: Fri, 2 Aug 2019 13:03:20 +0800 Subject: [PATCH] migrate nullish coalescing commit --- src/compiler/binder.ts | 10 +- src/compiler/checker.ts | 9 +- src/compiler/factory.ts | 4 + src/compiler/parser.ts | 1 + src/compiler/scanner.ts | 4 + src/compiler/transformers/esnext.ts | 32 ++++ src/compiler/types.ts | 2 + src/compiler/utilities.ts | 1 + .../reference/nullishCoalescingOperator1.js | 60 ++++++ .../nullishCoalescingOperator1.symbols | 125 +++++++++++++ .../nullishCoalescingOperator1.types | 172 ++++++++++++++++++ .../reference/nullishCoalescingOperator2.js | 33 ++++ .../nullishCoalescingOperator2.symbols | 65 +++++++ .../nullishCoalescingOperator2.types | 94 ++++++++++ .../nullishCoalescingOperator1.ts | 42 +++++ .../nullishCoalescingOperator2.ts | 22 +++ 16 files changed, 671 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/nullishCoalescingOperator1.js create mode 100644 tests/baselines/reference/nullishCoalescingOperator1.symbols create mode 100644 tests/baselines/reference/nullishCoalescingOperator1.types create mode 100644 tests/baselines/reference/nullishCoalescingOperator2.js create mode 100644 tests/baselines/reference/nullishCoalescingOperator2.symbols create mode 100644 tests/baselines/reference/nullishCoalescingOperator2.types create mode 100644 tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator1.ts create mode 100644 tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator2.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 660b19a587276..f245cef5a51d4 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -934,7 +934,8 @@ namespace ts { else { return node.kind === SyntaxKind.BinaryExpression && ( (node).operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || - (node).operatorToken.kind === SyntaxKind.BarBarToken); + (node).operatorToken.kind === SyntaxKind.BarBarToken || + (node).operatorToken.kind === SyntaxKind.QuestionQuestionToken); } } } @@ -1367,7 +1368,7 @@ 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) { if (isTopLevelLogicalExpression(node)) { const postExpressionLabel = createBranchLabel(); bindLogicalExpression(node, postExpressionLabel, postExpressionLabel); @@ -3147,7 +3148,10 @@ namespace ts { const operatorTokenKind = node.operatorToken.kind; const leftKind = node.left.kind; - if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) { + if (operatorTokenKind === SyntaxKind.QuestionQuestionToken) { + transformFlags |= TransformFlags.AssertESNext; + } + else if (operatorTokenKind === SyntaxKind.EqualsToken && leftKind === SyntaxKind.ObjectLiteralExpression) { // Destructuring object assignments with are ES2015 syntax // and possibly ES2018 if they contain rest transformFlags |= TransformFlags.AssertES2018 | TransformFlags.AssertES2015 | TransformFlags.AssertDestructuringAssignment; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a4ad3af7d9a35..df489a7c737e5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11524,7 +11524,7 @@ namespace ts { return isContextSensitive((node).whenTrue) || isContextSensitive((node).whenFalse); case SyntaxKind.BinaryExpression: - return (node).operatorToken.kind === SyntaxKind.BarBarToken && + return ((node).operatorToken.kind === SyntaxKind.BarBarToken || (node).operatorToken.kind === SyntaxKind.QuestionQuestionToken) && (isContextSensitive((node).left) || isContextSensitive((node).right)); case SyntaxKind.PropertyAssignment: return isContextSensitive((node).initializer); @@ -18477,6 +18477,7 @@ namespace ts { } return contextSensitive === true ? getTypeOfExpression(left) : contextSensitive; case SyntaxKind.BarBarToken: + case SyntaxKind.QuestionQuestionToken: // When an || expression has a contextual type, the operands are contextually typed by that type, except // when that type originates in a binding pattern, the right operand is contextually typed by the type of // the left operand. When an || expression has no contextual type, the right operand is contextually typed @@ -23761,7 +23762,7 @@ namespace ts { return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword); } let leftType: Type; - if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken) { + if (operator === SyntaxKind.AmpersandAmpersandToken || operator === SyntaxKind.BarBarToken || operator === SyntaxKind.QuestionQuestionToken) { leftType = checkTruthinessExpression(left, checkMode); } else { @@ -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]) : + leftType; case SyntaxKind.EqualsToken: const declKind = isBinaryExpression(left.parent) ? getAssignmentDeclarationKind(left.parent) : AssignmentDeclarationKind.None; checkAssignmentDeclaration(declKind, rightType); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index f67ec39b0a47e..c1740b53118a9 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -3044,6 +3044,10 @@ namespace ts { return createBinary(left, SyntaxKind.BarBarToken, right); } + export function createNullishCoalescing(left: Expression, right: Expression) { + return createBinary(left, SyntaxKind.QuestionQuestionToken, right); + } + export function createLogicalNot(operand: Expression) { return createPrefix(SyntaxKind.ExclamationToken, operand); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c38e4f67fe287..d770b2db2b854 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4659,6 +4659,7 @@ namespace ts { case SyntaxKind.ExclamationEqualsEqualsToken: // foo !== case SyntaxKind.AmpersandAmpersandToken: // foo && case SyntaxKind.BarBarToken: // foo || + case SyntaxKind.QuestionQuestionToken: // foo ?? case SyntaxKind.CaretToken: // foo ^ case SyntaxKind.AmpersandToken: // foo & case SyntaxKind.BarToken: // foo | diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 36ac8adfa9053..2d335c9cb98e6 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -182,6 +182,7 @@ namespace ts { "&&": SyntaxKind.AmpersandAmpersandToken, "||": SyntaxKind.BarBarToken, "?": SyntaxKind.QuestionToken, + "??": SyntaxKind.QuestionQuestionToken, ":": SyntaxKind.ColonToken, "=": SyntaxKind.EqualsToken, "+=": SyntaxKind.PlusEqualsToken, @@ -1778,6 +1779,9 @@ namespace ts { pos++; return token = SyntaxKind.GreaterThanToken; case CharacterCodes.question: + if (text.charCodeAt(pos + 1) === CharacterCodes.question) { + return pos += 2, token = SyntaxKind.QuestionQuestionToken; + } pos++; return token = SyntaxKind.QuestionToken; case CharacterCodes.openBracket: diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 80debb46f8a04..d9a09a933cb16 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -16,9 +16,41 @@ namespace ts { return node; } switch (node.kind) { + case SyntaxKind.BinaryExpression: + if ((node).operatorToken.kind === SyntaxKind.QuestionQuestionToken) { + return transformNullishCoalescingExpression(node) + } default: return visitEachChild(node, visitor, context); } } + + function createNotUndefinedCondition(node: Expression) { + return isIdentifier(node) && !isGeneratedIdentifier(node) + ? createStrictInequality(createTypeOf(node), createLiteral("undefined")) + : createStrictInequality(node, createVoidZero()); + } + + function createNotNullCondition(node: Expression) { + return createStrictInequality(node, createNull()); + } + + function transformNullishCoalescingExpression(node: BinaryExpression) { + const expressions: Expression[] = []; + let left = visitNode(node.left, visitor, isExpression); + if (!isIdentifier(left)) { + const temp = createTempVariable(/*recordTempVariable*/ undefined); + expressions.push(createAssignment(temp, left)); + left = temp; + } + expressions.push( + createConditional( + createLogicalAnd( + createNotUndefinedCondition(left), + createNotNullCondition(left)), + left, + visitNode(node.right, visitor, isExpression))); + return inlineExpressions(expressions); + } } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 845c63b707bc8..ef389b3860fd7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -181,6 +181,7 @@ namespace ts { QuestionToken, ColonToken, AtToken, + QuestionQuestionToken, /** Only the JSDoc scanner produces BacktickToken. The normal scanner produces NoSubstitutionTemplateLiteral and related kinds. */ BacktickToken, // Assignments @@ -1497,6 +1498,7 @@ namespace ts { export type LogicalOperator = SyntaxKind.AmpersandAmpersandToken | SyntaxKind.BarBarToken + | SyntaxKind.QuestionQuestionToken ; // see: https://tc39.github.io/ecma262/#prod-LogicalANDExpression diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 0e2488a02331c..6017bc6096162 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2988,6 +2988,7 @@ namespace ts { export function getBinaryOperatorPrecedence(kind: SyntaxKind): number { switch (kind) { + case SyntaxKind.QuestionQuestionToken: case SyntaxKind.BarBarToken: return 5; case SyntaxKind.AmpersandAmpersandToken: diff --git a/tests/baselines/reference/nullishCoalescingOperator1.js b/tests/baselines/reference/nullishCoalescingOperator1.js new file mode 100644 index 0000000000000..f94f87acc3a8f --- /dev/null +++ b/tests/baselines/reference/nullishCoalescingOperator1.js @@ -0,0 +1,60 @@ +//// [nullishCoalescingOperator1.ts] +declare const a1: string | undefined | null +declare const a2: string | undefined | null +declare const a3: string | undefined | null +declare const a4: string | undefined | null + +declare const b1: number | undefined | null +declare const b2: number | undefined | null +declare const b3: number | undefined | null +declare const b4: number | undefined | null + +declare const c1: boolean | undefined | null +declare const c2: boolean | undefined | null +declare const c3: boolean | undefined | null +declare const c4: boolean | undefined | null + +interface I { a: string } +declare const d1: I | undefined | null +declare const d2: I | undefined | null +declare const d3: I | undefined | null +declare const d4: I | undefined | null + +const aa1 = a1 ?? 'whatever'; +const aa2 = a2 ?? 'whatever'; +const aa3 = a3 ?? 'whatever'; +const aa4 = a4 ?? 'whatever'; + +const bb1 = b1 ?? 1; +const bb2 = b2 ?? 1; +const bb3 = b3 ?? 1; +const bb4 = b4 ?? 1; + +const cc1 = c1 ?? true; +const cc2 = c2 ?? true; +const cc3 = c3 ?? true; +const cc4 = c4 ?? true; + +const dd1 = d1 ?? {b: 1}; +const dd2 = d2 ?? {b: 1}; +const dd3 = d3 ?? {b: 1}; +const dd4 = d4 ?? {b: 1}; + +//// [nullishCoalescingOperator1.js] +"use strict"; +var aa1 = typeof a1 !== "undefined" && a1 !== null ? a1 : 'whatever'; +var aa2 = typeof a2 !== "undefined" && a2 !== null ? a2 : 'whatever'; +var aa3 = typeof a3 !== "undefined" && a3 !== null ? a3 : 'whatever'; +var aa4 = typeof a4 !== "undefined" && a4 !== null ? a4 : 'whatever'; +var bb1 = typeof b1 !== "undefined" && b1 !== null ? b1 : 1; +var bb2 = typeof b2 !== "undefined" && b2 !== null ? b2 : 1; +var bb3 = typeof b3 !== "undefined" && b3 !== null ? b3 : 1; +var bb4 = typeof b4 !== "undefined" && b4 !== null ? b4 : 1; +var cc1 = typeof c1 !== "undefined" && c1 !== null ? c1 : true; +var cc2 = typeof c2 !== "undefined" && c2 !== null ? c2 : true; +var cc3 = typeof c3 !== "undefined" && c3 !== null ? c3 : true; +var cc4 = typeof c4 !== "undefined" && c4 !== null ? c4 : true; +var dd1 = typeof d1 !== "undefined" && d1 !== null ? d1 : { b: 1 }; +var dd2 = typeof d2 !== "undefined" && d2 !== null ? d2 : { b: 1 }; +var dd3 = typeof d3 !== "undefined" && d3 !== null ? d3 : { b: 1 }; +var dd4 = typeof d4 !== "undefined" && d4 !== null ? d4 : { b: 1 }; diff --git a/tests/baselines/reference/nullishCoalescingOperator1.symbols b/tests/baselines/reference/nullishCoalescingOperator1.symbols new file mode 100644 index 0000000000000..fb95dee5096a6 --- /dev/null +++ b/tests/baselines/reference/nullishCoalescingOperator1.symbols @@ -0,0 +1,125 @@ +=== tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator1.ts === +declare const a1: string | undefined | null +>a1 : Symbol(a1, Decl(nullishCoalescingOperator1.ts, 0, 13)) + +declare const a2: string | undefined | null +>a2 : Symbol(a2, Decl(nullishCoalescingOperator1.ts, 1, 13)) + +declare const a3: string | undefined | null +>a3 : Symbol(a3, Decl(nullishCoalescingOperator1.ts, 2, 13)) + +declare const a4: string | undefined | null +>a4 : Symbol(a4, Decl(nullishCoalescingOperator1.ts, 3, 13)) + +declare const b1: number | undefined | null +>b1 : Symbol(b1, Decl(nullishCoalescingOperator1.ts, 5, 13)) + +declare const b2: number | undefined | null +>b2 : Symbol(b2, Decl(nullishCoalescingOperator1.ts, 6, 13)) + +declare const b3: number | undefined | null +>b3 : Symbol(b3, Decl(nullishCoalescingOperator1.ts, 7, 13)) + +declare const b4: number | undefined | null +>b4 : Symbol(b4, Decl(nullishCoalescingOperator1.ts, 8, 13)) + +declare const c1: boolean | undefined | null +>c1 : Symbol(c1, Decl(nullishCoalescingOperator1.ts, 10, 13)) + +declare const c2: boolean | undefined | null +>c2 : Symbol(c2, Decl(nullishCoalescingOperator1.ts, 11, 13)) + +declare const c3: boolean | undefined | null +>c3 : Symbol(c3, Decl(nullishCoalescingOperator1.ts, 12, 13)) + +declare const c4: boolean | undefined | null +>c4 : Symbol(c4, Decl(nullishCoalescingOperator1.ts, 13, 13)) + +interface I { a: string } +>I : Symbol(I, Decl(nullishCoalescingOperator1.ts, 13, 44)) +>a : Symbol(I.a, Decl(nullishCoalescingOperator1.ts, 15, 13)) + +declare const d1: I | undefined | null +>d1 : Symbol(d1, Decl(nullishCoalescingOperator1.ts, 16, 13)) +>I : Symbol(I, Decl(nullishCoalescingOperator1.ts, 13, 44)) + +declare const d2: I | undefined | null +>d2 : Symbol(d2, Decl(nullishCoalescingOperator1.ts, 17, 13)) +>I : Symbol(I, Decl(nullishCoalescingOperator1.ts, 13, 44)) + +declare const d3: I | undefined | null +>d3 : Symbol(d3, Decl(nullishCoalescingOperator1.ts, 18, 13)) +>I : Symbol(I, Decl(nullishCoalescingOperator1.ts, 13, 44)) + +declare const d4: I | undefined | null +>d4 : Symbol(d4, Decl(nullishCoalescingOperator1.ts, 19, 13)) +>I : Symbol(I, Decl(nullishCoalescingOperator1.ts, 13, 44)) + +const aa1 = a1 ?? 'whatever'; +>aa1 : Symbol(aa1, Decl(nullishCoalescingOperator1.ts, 21, 5)) +>a1 : Symbol(a1, Decl(nullishCoalescingOperator1.ts, 0, 13)) + +const aa2 = a2 ?? 'whatever'; +>aa2 : Symbol(aa2, Decl(nullishCoalescingOperator1.ts, 22, 5)) +>a2 : Symbol(a2, Decl(nullishCoalescingOperator1.ts, 1, 13)) + +const aa3 = a3 ?? 'whatever'; +>aa3 : Symbol(aa3, Decl(nullishCoalescingOperator1.ts, 23, 5)) +>a3 : Symbol(a3, Decl(nullishCoalescingOperator1.ts, 2, 13)) + +const aa4 = a4 ?? 'whatever'; +>aa4 : Symbol(aa4, Decl(nullishCoalescingOperator1.ts, 24, 5)) +>a4 : Symbol(a4, Decl(nullishCoalescingOperator1.ts, 3, 13)) + +const bb1 = b1 ?? 1; +>bb1 : Symbol(bb1, Decl(nullishCoalescingOperator1.ts, 26, 5)) +>b1 : Symbol(b1, Decl(nullishCoalescingOperator1.ts, 5, 13)) + +const bb2 = b2 ?? 1; +>bb2 : Symbol(bb2, Decl(nullishCoalescingOperator1.ts, 27, 5)) +>b2 : Symbol(b2, Decl(nullishCoalescingOperator1.ts, 6, 13)) + +const bb3 = b3 ?? 1; +>bb3 : Symbol(bb3, Decl(nullishCoalescingOperator1.ts, 28, 5)) +>b3 : Symbol(b3, Decl(nullishCoalescingOperator1.ts, 7, 13)) + +const bb4 = b4 ?? 1; +>bb4 : Symbol(bb4, Decl(nullishCoalescingOperator1.ts, 29, 5)) +>b4 : Symbol(b4, Decl(nullishCoalescingOperator1.ts, 8, 13)) + +const cc1 = c1 ?? true; +>cc1 : Symbol(cc1, Decl(nullishCoalescingOperator1.ts, 31, 5)) +>c1 : Symbol(c1, Decl(nullishCoalescingOperator1.ts, 10, 13)) + +const cc2 = c2 ?? true; +>cc2 : Symbol(cc2, Decl(nullishCoalescingOperator1.ts, 32, 5)) +>c2 : Symbol(c2, Decl(nullishCoalescingOperator1.ts, 11, 13)) + +const cc3 = c3 ?? true; +>cc3 : Symbol(cc3, Decl(nullishCoalescingOperator1.ts, 33, 5)) +>c3 : Symbol(c3, Decl(nullishCoalescingOperator1.ts, 12, 13)) + +const cc4 = c4 ?? true; +>cc4 : Symbol(cc4, Decl(nullishCoalescingOperator1.ts, 34, 5)) +>c4 : Symbol(c4, Decl(nullishCoalescingOperator1.ts, 13, 13)) + +const dd1 = d1 ?? {b: 1}; +>dd1 : Symbol(dd1, Decl(nullishCoalescingOperator1.ts, 36, 5)) +>d1 : Symbol(d1, Decl(nullishCoalescingOperator1.ts, 16, 13)) +>b : Symbol(b, Decl(nullishCoalescingOperator1.ts, 36, 19)) + +const dd2 = d2 ?? {b: 1}; +>dd2 : Symbol(dd2, Decl(nullishCoalescingOperator1.ts, 37, 5)) +>d2 : Symbol(d2, Decl(nullishCoalescingOperator1.ts, 17, 13)) +>b : Symbol(b, Decl(nullishCoalescingOperator1.ts, 37, 19)) + +const dd3 = d3 ?? {b: 1}; +>dd3 : Symbol(dd3, Decl(nullishCoalescingOperator1.ts, 38, 5)) +>d3 : Symbol(d3, Decl(nullishCoalescingOperator1.ts, 18, 13)) +>b : Symbol(b, Decl(nullishCoalescingOperator1.ts, 38, 19)) + +const dd4 = d4 ?? {b: 1}; +>dd4 : Symbol(dd4, Decl(nullishCoalescingOperator1.ts, 39, 5)) +>d4 : Symbol(d4, Decl(nullishCoalescingOperator1.ts, 19, 13)) +>b : Symbol(b, Decl(nullishCoalescingOperator1.ts, 39, 19)) + diff --git a/tests/baselines/reference/nullishCoalescingOperator1.types b/tests/baselines/reference/nullishCoalescingOperator1.types new file mode 100644 index 0000000000000..0e800540ee8b3 --- /dev/null +++ b/tests/baselines/reference/nullishCoalescingOperator1.types @@ -0,0 +1,172 @@ +=== tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator1.ts === +declare const a1: string | undefined | null +>a1 : string | null | undefined +>null : null + +declare const a2: string | undefined | null +>a2 : string | null | undefined +>null : null + +declare const a3: string | undefined | null +>a3 : string | null | undefined +>null : null + +declare const a4: string | undefined | null +>a4 : string | null | undefined +>null : null + +declare const b1: number | undefined | null +>b1 : number | null | undefined +>null : null + +declare const b2: number | undefined | null +>b2 : number | null | undefined +>null : null + +declare const b3: number | undefined | null +>b3 : number | null | undefined +>null : null + +declare const b4: number | undefined | null +>b4 : number | null | undefined +>null : null + +declare const c1: boolean | undefined | null +>c1 : boolean | null | undefined +>null : null + +declare const c2: boolean | undefined | null +>c2 : boolean | null | undefined +>null : null + +declare const c3: boolean | undefined | null +>c3 : boolean | null | undefined +>null : null + +declare const c4: boolean | undefined | null +>c4 : boolean | null | undefined +>null : null + +interface I { a: string } +>a : string + +declare const d1: I | undefined | null +>d1 : I | null | undefined +>null : null + +declare const d2: I | undefined | null +>d2 : I | null | undefined +>null : null + +declare const d3: I | undefined | null +>d3 : I | null | undefined +>null : null + +declare const d4: I | undefined | null +>d4 : I | null | undefined +>null : null + +const aa1 = a1 ?? 'whatever'; +>aa1 : string +>a1 ?? 'whatever' : string +>a1 : string | null | undefined +>'whatever' : "whatever" + +const aa2 = a2 ?? 'whatever'; +>aa2 : string +>a2 ?? 'whatever' : string +>a2 : string | null | undefined +>'whatever' : "whatever" + +const aa3 = a3 ?? 'whatever'; +>aa3 : string +>a3 ?? 'whatever' : string +>a3 : string | null | undefined +>'whatever' : "whatever" + +const aa4 = a4 ?? 'whatever'; +>aa4 : string +>a4 ?? 'whatever' : string +>a4 : string | null | undefined +>'whatever' : "whatever" + +const bb1 = b1 ?? 1; +>bb1 : number +>b1 ?? 1 : number +>b1 : number | null | undefined +>1 : 1 + +const bb2 = b2 ?? 1; +>bb2 : number +>b2 ?? 1 : number +>b2 : number | null | undefined +>1 : 1 + +const bb3 = b3 ?? 1; +>bb3 : number +>b3 ?? 1 : number +>b3 : number | null | undefined +>1 : 1 + +const bb4 = b4 ?? 1; +>bb4 : number +>b4 ?? 1 : number +>b4 : number | null | undefined +>1 : 1 + +const cc1 = c1 ?? true; +>cc1 : boolean +>c1 ?? true : boolean +>c1 : boolean | null | undefined +>true : true + +const cc2 = c2 ?? true; +>cc2 : boolean +>c2 ?? true : boolean +>c2 : boolean | null | undefined +>true : true + +const cc3 = c3 ?? true; +>cc3 : boolean +>c3 ?? true : boolean +>c3 : boolean | null | undefined +>true : true + +const cc4 = c4 ?? true; +>cc4 : boolean +>c4 ?? true : boolean +>c4 : boolean | null | undefined +>true : true + +const dd1 = d1 ?? {b: 1}; +>dd1 : I | { b: number; } +>d1 ?? {b: 1} : I | { b: number; } +>d1 : I | null | undefined +>{b: 1} : { b: number; } +>b : number +>1 : 1 + +const dd2 = d2 ?? {b: 1}; +>dd2 : I | { b: number; } +>d2 ?? {b: 1} : I | { b: number; } +>d2 : I | null | undefined +>{b: 1} : { b: number; } +>b : number +>1 : 1 + +const dd3 = d3 ?? {b: 1}; +>dd3 : I | { b: number; } +>d3 ?? {b: 1} : I | { b: number; } +>d3 : I | null | undefined +>{b: 1} : { b: number; } +>b : number +>1 : 1 + +const dd4 = d4 ?? {b: 1}; +>dd4 : I | { b: number; } +>d4 ?? {b: 1} : I | { b: number; } +>d4 : I | null | undefined +>{b: 1} : { b: number; } +>b : number +>1 : 1 + diff --git a/tests/baselines/reference/nullishCoalescingOperator2.js b/tests/baselines/reference/nullishCoalescingOperator2.js new file mode 100644 index 0000000000000..133eb55d8b542 --- /dev/null +++ b/tests/baselines/reference/nullishCoalescingOperator2.js @@ -0,0 +1,33 @@ +//// [nullishCoalescingOperator2.ts] +declare const a1: 'literal' | undefined | null +declare const a2: '' | undefined | null +declare const a3: 1 | undefined | null +declare const a4: 0 | undefined | null +declare const a5: true | undefined | null +declare const a6: false | undefined | null +declare const a7: unknown | null +declare const a8: never | null +declare const a9: any | null + + +const aa1 = a1 ?? 'whatever' +const aa2 = a2 ?? 'whatever' +const aa3 = a3 ?? 'whatever' +const aa4 = a4 ?? 'whatever' +const aa5 = a5 ?? 'whatever' +const aa6 = a6 ?? 'whatever' +const aa7 = a7 ?? 'whatever' +const aa8 = a8 ?? 'whatever' +const aa9 = a9 ?? 'whatever' + +//// [nullishCoalescingOperator2.js] +"use strict"; +var aa1 = typeof a1 !== "undefined" && a1 !== null ? a1 : 'whatever'; +var aa2 = typeof a2 !== "undefined" && a2 !== null ? a2 : 'whatever'; +var aa3 = typeof a3 !== "undefined" && a3 !== null ? a3 : 'whatever'; +var aa4 = typeof a4 !== "undefined" && a4 !== null ? a4 : 'whatever'; +var aa5 = typeof a5 !== "undefined" && a5 !== null ? a5 : 'whatever'; +var aa6 = typeof a6 !== "undefined" && a6 !== null ? a6 : 'whatever'; +var aa7 = typeof a7 !== "undefined" && a7 !== null ? a7 : 'whatever'; +var aa8 = typeof a8 !== "undefined" && a8 !== null ? a8 : 'whatever'; +var aa9 = typeof a9 !== "undefined" && a9 !== null ? a9 : 'whatever'; diff --git a/tests/baselines/reference/nullishCoalescingOperator2.symbols b/tests/baselines/reference/nullishCoalescingOperator2.symbols new file mode 100644 index 0000000000000..d712165683405 --- /dev/null +++ b/tests/baselines/reference/nullishCoalescingOperator2.symbols @@ -0,0 +1,65 @@ +=== tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator2.ts === +declare const a1: 'literal' | undefined | null +>a1 : Symbol(a1, Decl(nullishCoalescingOperator2.ts, 0, 13)) + +declare const a2: '' | undefined | null +>a2 : Symbol(a2, Decl(nullishCoalescingOperator2.ts, 1, 13)) + +declare const a3: 1 | undefined | null +>a3 : Symbol(a3, Decl(nullishCoalescingOperator2.ts, 2, 13)) + +declare const a4: 0 | undefined | null +>a4 : Symbol(a4, Decl(nullishCoalescingOperator2.ts, 3, 13)) + +declare const a5: true | undefined | null +>a5 : Symbol(a5, Decl(nullishCoalescingOperator2.ts, 4, 13)) + +declare const a6: false | undefined | null +>a6 : Symbol(a6, Decl(nullishCoalescingOperator2.ts, 5, 13)) + +declare const a7: unknown | null +>a7 : Symbol(a7, Decl(nullishCoalescingOperator2.ts, 6, 13)) + +declare const a8: never | null +>a8 : Symbol(a8, Decl(nullishCoalescingOperator2.ts, 7, 13)) + +declare const a9: any | null +>a9 : Symbol(a9, Decl(nullishCoalescingOperator2.ts, 8, 13)) + + +const aa1 = a1 ?? 'whatever' +>aa1 : Symbol(aa1, Decl(nullishCoalescingOperator2.ts, 11, 5)) +>a1 : Symbol(a1, Decl(nullishCoalescingOperator2.ts, 0, 13)) + +const aa2 = a2 ?? 'whatever' +>aa2 : Symbol(aa2, Decl(nullishCoalescingOperator2.ts, 12, 5)) +>a2 : Symbol(a2, Decl(nullishCoalescingOperator2.ts, 1, 13)) + +const aa3 = a3 ?? 'whatever' +>aa3 : Symbol(aa3, Decl(nullishCoalescingOperator2.ts, 13, 5)) +>a3 : Symbol(a3, Decl(nullishCoalescingOperator2.ts, 2, 13)) + +const aa4 = a4 ?? 'whatever' +>aa4 : Symbol(aa4, Decl(nullishCoalescingOperator2.ts, 14, 5)) +>a4 : Symbol(a4, Decl(nullishCoalescingOperator2.ts, 3, 13)) + +const aa5 = a5 ?? 'whatever' +>aa5 : Symbol(aa5, Decl(nullishCoalescingOperator2.ts, 15, 5)) +>a5 : Symbol(a5, Decl(nullishCoalescingOperator2.ts, 4, 13)) + +const aa6 = a6 ?? 'whatever' +>aa6 : Symbol(aa6, Decl(nullishCoalescingOperator2.ts, 16, 5)) +>a6 : Symbol(a6, Decl(nullishCoalescingOperator2.ts, 5, 13)) + +const aa7 = a7 ?? 'whatever' +>aa7 : Symbol(aa7, Decl(nullishCoalescingOperator2.ts, 17, 5)) +>a7 : Symbol(a7, Decl(nullishCoalescingOperator2.ts, 6, 13)) + +const aa8 = a8 ?? 'whatever' +>aa8 : Symbol(aa8, Decl(nullishCoalescingOperator2.ts, 18, 5)) +>a8 : Symbol(a8, Decl(nullishCoalescingOperator2.ts, 7, 13)) + +const aa9 = a9 ?? 'whatever' +>aa9 : Symbol(aa9, Decl(nullishCoalescingOperator2.ts, 19, 5)) +>a9 : Symbol(a9, Decl(nullishCoalescingOperator2.ts, 8, 13)) + diff --git a/tests/baselines/reference/nullishCoalescingOperator2.types b/tests/baselines/reference/nullishCoalescingOperator2.types new file mode 100644 index 0000000000000..dd1e31c4038c4 --- /dev/null +++ b/tests/baselines/reference/nullishCoalescingOperator2.types @@ -0,0 +1,94 @@ +=== tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator2.ts === +declare const a1: 'literal' | undefined | null +>a1 : "literal" | null | undefined +>null : null + +declare const a2: '' | undefined | null +>a2 : "" | null | undefined +>null : null + +declare const a3: 1 | undefined | null +>a3 : 1 | null | undefined +>null : null + +declare const a4: 0 | undefined | null +>a4 : 0 | null | undefined +>null : null + +declare const a5: true | undefined | null +>a5 : true | null | undefined +>true : true +>null : null + +declare const a6: false | undefined | null +>a6 : false | null | undefined +>false : false +>null : null + +declare const a7: unknown | null +>a7 : unknown +>null : null + +declare const a8: never | null +>a8 : null +>null : null + +declare const a9: any | null +>a9 : any +>null : null + + +const aa1 = a1 ?? 'whatever' +>aa1 : "literal" | "whatever" +>a1 ?? 'whatever' : "literal" | "whatever" +>a1 : "literal" | null | undefined +>'whatever' : "whatever" + +const aa2 = a2 ?? 'whatever' +>aa2 : "" | "whatever" +>a2 ?? 'whatever' : "" | "whatever" +>a2 : "" | null | undefined +>'whatever' : "whatever" + +const aa3 = a3 ?? 'whatever' +>aa3 : 1 | "whatever" +>a3 ?? 'whatever' : 1 | "whatever" +>a3 : 1 | null | undefined +>'whatever' : "whatever" + +const aa4 = a4 ?? 'whatever' +>aa4 : 0 | "whatever" +>a4 ?? 'whatever' : 0 | "whatever" +>a4 : 0 | null | undefined +>'whatever' : "whatever" + +const aa5 = a5 ?? 'whatever' +>aa5 : true | "whatever" +>a5 ?? 'whatever' : true | "whatever" +>a5 : true | null | undefined +>'whatever' : "whatever" + +const aa6 = a6 ?? 'whatever' +>aa6 : false | "whatever" +>a6 ?? 'whatever' : false | "whatever" +>a6 : false | null | undefined +>'whatever' : "whatever" + +const aa7 = a7 ?? 'whatever' +>aa7 : unknown +>a7 ?? 'whatever' : unknown +>a7 : unknown +>'whatever' : "whatever" + +const aa8 = a8 ?? 'whatever' +>aa8 : "whatever" +>a8 ?? 'whatever' : "whatever" +>a8 : null +>'whatever' : "whatever" + +const aa9 = a9 ?? 'whatever' +>aa9 : any +>a9 ?? 'whatever' : any +>a9 : any +>'whatever' : "whatever" + diff --git a/tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator1.ts b/tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator1.ts new file mode 100644 index 0000000000000..80f0c64e7d94d --- /dev/null +++ b/tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator1.ts @@ -0,0 +1,42 @@ +// @strict: true + +declare const a1: string | undefined | null +declare const a2: string | undefined | null +declare const a3: string | undefined | null +declare const a4: string | undefined | null + +declare const b1: number | undefined | null +declare const b2: number | undefined | null +declare const b3: number | undefined | null +declare const b4: number | undefined | null + +declare const c1: boolean | undefined | null +declare const c2: boolean | undefined | null +declare const c3: boolean | undefined | null +declare const c4: boolean | undefined | null + +interface I { a: string } +declare const d1: I | undefined | null +declare const d2: I | undefined | null +declare const d3: I | undefined | null +declare const d4: I | undefined | null + +const aa1 = a1 ?? 'whatever'; +const aa2 = a2 ?? 'whatever'; +const aa3 = a3 ?? 'whatever'; +const aa4 = a4 ?? 'whatever'; + +const bb1 = b1 ?? 1; +const bb2 = b2 ?? 1; +const bb3 = b3 ?? 1; +const bb4 = b4 ?? 1; + +const cc1 = c1 ?? true; +const cc2 = c2 ?? true; +const cc3 = c3 ?? true; +const cc4 = c4 ?? true; + +const dd1 = d1 ?? {b: 1}; +const dd2 = d2 ?? {b: 1}; +const dd3 = d3 ?? {b: 1}; +const dd4 = d4 ?? {b: 1}; \ No newline at end of file diff --git a/tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator2.ts b/tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator2.ts new file mode 100644 index 0000000000000..5d5761aeec534 --- /dev/null +++ b/tests/cases/conformance/expressions/nullishCoalescingOperator/nullishCoalescingOperator2.ts @@ -0,0 +1,22 @@ +// @strict: true + +declare const a1: 'literal' | undefined | null +declare const a2: '' | undefined | null +declare const a3: 1 | undefined | null +declare const a4: 0 | undefined | null +declare const a5: true | undefined | null +declare const a6: false | undefined | null +declare const a7: unknown | null +declare const a8: never | null +declare const a9: any | null + + +const aa1 = a1 ?? 'whatever' +const aa2 = a2 ?? 'whatever' +const aa3 = a3 ?? 'whatever' +const aa4 = a4 ?? 'whatever' +const aa5 = a5 ?? 'whatever' +const aa6 = a6 ?? 'whatever' +const aa7 = a7 ?? 'whatever' +const aa8 = a8 ?? 'whatever' +const aa9 = a9 ?? 'whatever' \ No newline at end of file