From b9e26e7649f73fa449e4339eb12402d5d8e87def Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 6 Feb 2016 08:37:09 -0800 Subject: [PATCH 1/4] Correct handling of intersection types in allConstituentTypesHaveKind --- src/compiler/checker.ts | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 65cb3df785f9c..6fd464c38bc70 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -10337,9 +10337,8 @@ namespace ts { const widenedType = getWidenedType(exprType); // Permit 'number[] | "foo"' to be asserted to 'string'. - const bothAreStringLike = - someConstituentTypeHasKind(targetType, TypeFlags.StringLike) && - someConstituentTypeHasKind(widenedType, TypeFlags.StringLike); + const bothAreStringLike = someConstituentTypeHasKind(targetType, TypeFlags.StringLike) && + someConstituentTypeHasKind(widenedType, TypeFlags.StringLike); if (!bothAreStringLike && !(isTypeAssignableTo(targetType, widenedType))) { checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other); } @@ -10594,7 +10593,7 @@ namespace ts { } // Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions. - if (returnType === voidType || isTypeAny(returnType) || (returnType && (returnType.flags & TypeFlags.Union) && someConstituentTypeHasKind(returnType, TypeFlags.Any | TypeFlags.Void))) { + if (returnType && someConstituentTypeHasKind(returnType, TypeFlags.Any | TypeFlags.Void)) { return; } @@ -10882,38 +10881,47 @@ namespace ts { return numberType; } - // Just like isTypeOfKind below, except that it returns true if *any* constituent - // has this kind. + // Return true if type might be of the given kind. A union or intersection type might be of a given + // kind if at least one constituent type is of the given kind. function someConstituentTypeHasKind(type: Type, kind: TypeFlags): boolean { if (type.flags & kind) { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { const types = (type).types; - for (const current of types) { - if (current.flags & kind) { + for (const t of types) { + if (someConstituentTypeHasKind(t, kind)) { return true; } } - return false; } return false; } - // Return true if type has the given flags, or is a union or intersection type composed of types that all have those flags. + // Return true if type is of the given kind. A union type is of a given kind if all constituent types + // are of the given kind. An intersection type is of a given kind if at least one constituent type is + // of the given kind. function allConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean { if (type.flags & kind) { return true; } - if (type.flags & TypeFlags.UnionOrIntersection) { + if (type.flags & TypeFlags.Union) { const types = (type).types; - for (const current of types) { - if (!(current.flags & kind)) { + for (const t of types) { + if (!allConstituentTypesHaveKind(t, kind)) { return false; } } return true; } + if (type.flags & TypeFlags.Intersection) { + const types = (type).types; + for (const t of types) { + if (allConstituentTypesHaveKind(t, kind)) { + return true; + } + } + } return false; } From 6f85e13c72763443d758a1f473fcc49796472e0a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 6 Feb 2016 08:39:31 -0800 Subject: [PATCH 2/4] Rename allConstituentTypesHaveKind/someConstituentTypeHasKind to isTypeOfKind/maybeTypeOfKind --- src/compiler/checker.ts | 52 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6fd464c38bc70..22280a0572588 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5591,7 +5591,7 @@ namespace ts { } function hasExcessProperties(source: FreshObjectLiteralType, target: Type, reportErrors: boolean): boolean { - if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && someConstituentTypeHasKind(target, TypeFlags.ObjectType)) { + if (!(target.flags & TypeFlags.ObjectLiteralPatternWithComputedProperties) && maybeTypeOfKind(target, TypeFlags.ObjectType)) { for (const prop of getPropertiesOfObjectType(source)) { if (!isKnownProperty(target, prop.name)) { if (reportErrors) { @@ -8178,7 +8178,7 @@ namespace ts { } function isTypeAnyOrAllConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean { - return isTypeAny(type) || allConstituentTypesHaveKind(type, kind); + return isTypeAny(type) || isTypeOfKind(type, kind); } function isNumericLiteralName(name: string) { @@ -9684,7 +9684,7 @@ namespace ts { case SyntaxKind.ComputedPropertyName: const nameType = checkComputedPropertyName(element.name); - if (allConstituentTypesHaveKind(nameType, TypeFlags.ESSymbol)) { + if (isTypeOfKind(nameType, TypeFlags.ESSymbol)) { return nameType; } else { @@ -10337,8 +10337,8 @@ namespace ts { const widenedType = getWidenedType(exprType); // Permit 'number[] | "foo"' to be asserted to 'string'. - const bothAreStringLike = someConstituentTypeHasKind(targetType, TypeFlags.StringLike) && - someConstituentTypeHasKind(widenedType, TypeFlags.StringLike); + const bothAreStringLike = maybeTypeOfKind(targetType, TypeFlags.StringLike) && + maybeTypeOfKind(widenedType, TypeFlags.StringLike); if (!bothAreStringLike && !(isTypeAssignableTo(targetType, widenedType))) { checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other); } @@ -10593,7 +10593,7 @@ namespace ts { } // Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions. - if (returnType && someConstituentTypeHasKind(returnType, TypeFlags.Any | TypeFlags.Void)) { + if (returnType && maybeTypeOfKind(returnType, TypeFlags.Any | TypeFlags.Void)) { return; } @@ -10849,7 +10849,7 @@ namespace ts { case SyntaxKind.PlusToken: case SyntaxKind.MinusToken: case SyntaxKind.TildeToken: - if (someConstituentTypeHasKind(operandType, TypeFlags.ESSymbol)) { + if (maybeTypeOfKind(operandType, TypeFlags.ESSymbol)) { error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator)); } return numberType; @@ -10883,14 +10883,14 @@ namespace ts { // Return true if type might be of the given kind. A union or intersection type might be of a given // kind if at least one constituent type is of the given kind. - function someConstituentTypeHasKind(type: Type, kind: TypeFlags): boolean { + function maybeTypeOfKind(type: Type, kind: TypeFlags): boolean { if (type.flags & kind) { return true; } if (type.flags & TypeFlags.UnionOrIntersection) { const types = (type).types; for (const t of types) { - if (someConstituentTypeHasKind(t, kind)) { + if (maybeTypeOfKind(t, kind)) { return true; } } @@ -10901,14 +10901,14 @@ namespace ts { // Return true if type is of the given kind. A union type is of a given kind if all constituent types // are of the given kind. An intersection type is of a given kind if at least one constituent type is // of the given kind. - function allConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean { + function isTypeOfKind(type: Type, kind: TypeFlags): boolean { if (type.flags & kind) { return true; } if (type.flags & TypeFlags.Union) { const types = (type).types; for (const t of types) { - if (!allConstituentTypesHaveKind(t, kind)) { + if (!isTypeOfKind(t, kind)) { return false; } } @@ -10917,7 +10917,7 @@ namespace ts { if (type.flags & TypeFlags.Intersection) { const types = (type).types; for (const t of types) { - if (allConstituentTypesHaveKind(t, kind)) { + if (isTypeOfKind(t, kind)) { return true; } } @@ -10939,7 +10939,7 @@ namespace ts { // and the right operand to be of type Any or a subtype of the 'Function' interface type. // The result is always of the Boolean primitive type. // NOTE: do not raise error if leftType is unknown as related error was already reported - if (allConstituentTypesHaveKind(leftType, TypeFlags.Primitive)) { + if (isTypeOfKind(leftType, TypeFlags.Primitive)) { error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter); } // NOTE: do not raise error if right is unknown as related error was already reported @@ -11154,13 +11154,13 @@ namespace ts { if (rightType.flags & (TypeFlags.Undefined | TypeFlags.Null)) rightType = leftType; let resultType: Type; - if (allConstituentTypesHaveKind(leftType, TypeFlags.NumberLike) && allConstituentTypesHaveKind(rightType, TypeFlags.NumberLike)) { + if (isTypeOfKind(leftType, TypeFlags.NumberLike) && isTypeOfKind(rightType, TypeFlags.NumberLike)) { // Operands of an enum type are treated as having the primitive type Number. // If both operands are of the Number primitive type, the result is of the Number primitive type. resultType = numberType; } else { - if (allConstituentTypesHaveKind(leftType, TypeFlags.StringLike) || allConstituentTypesHaveKind(rightType, TypeFlags.StringLike)) { + if (isTypeOfKind(leftType, TypeFlags.StringLike) || isTypeOfKind(rightType, TypeFlags.StringLike)) { // If one or both operands are of the String primitive type, the result is of the String primitive type. resultType = stringType; } @@ -11198,7 +11198,7 @@ namespace ts { case SyntaxKind.EqualsEqualsEqualsToken: case SyntaxKind.ExclamationEqualsEqualsToken: // Permit 'number[] | "foo"' to be asserted to 'string'. - if (someConstituentTypeHasKind(leftType, TypeFlags.StringLike) && someConstituentTypeHasKind(rightType, TypeFlags.StringLike)) { + if (maybeTypeOfKind(leftType, TypeFlags.StringLike) && maybeTypeOfKind(rightType, TypeFlags.StringLike)) { return booleanType; } if (!isTypeAssignableTo(leftType, rightType) && !isTypeAssignableTo(rightType, leftType)) { @@ -11223,8 +11223,8 @@ namespace ts { // Return true if there was no error, false if there was an error. function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean { const offendingSymbolOperand = - someConstituentTypeHasKind(leftType, TypeFlags.ESSymbol) ? left : - someConstituentTypeHasKind(rightType, TypeFlags.ESSymbol) ? right : + maybeTypeOfKind(leftType, TypeFlags.ESSymbol) ? left : + maybeTypeOfKind(rightType, TypeFlags.ESSymbol) ? right : undefined; if (offendingSymbolOperand) { error(offendingSymbolOperand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(operator)); @@ -13712,7 +13712,7 @@ namespace ts { let hasDuplicateDefaultClause = false; const expressionType = checkExpression(node.expression); - const expressionTypeIsStringLike = someConstituentTypeHasKind(expressionType, TypeFlags.StringLike); + const expressionTypeIsStringLike = maybeTypeOfKind(expressionType, TypeFlags.StringLike); forEach(node.caseBlock.clauses, clause => { // Grammar check for duplicate default clauses, skip if we already report duplicate default clause if (clause.kind === SyntaxKind.DefaultClause && !hasDuplicateDefaultClause) { @@ -13736,7 +13736,7 @@ namespace ts { const expressionTypeIsAssignableToCaseType = // Permit 'number[] | "foo"' to be asserted to 'string'. - (expressionTypeIsStringLike && someConstituentTypeHasKind(caseType, TypeFlags.StringLike)) || + (expressionTypeIsStringLike && maybeTypeOfKind(caseType, TypeFlags.StringLike)) || isTypeAssignableTo(expressionType, caseType); if (!expressionTypeIsAssignableToCaseType) { @@ -15942,22 +15942,22 @@ namespace ts { else if (type.flags & TypeFlags.Any) { return TypeReferenceSerializationKind.ObjectType; } - else if (allConstituentTypesHaveKind(type, TypeFlags.Void)) { + else if (isTypeOfKind(type, TypeFlags.Void)) { return TypeReferenceSerializationKind.VoidType; } - else if (allConstituentTypesHaveKind(type, TypeFlags.Boolean)) { + else if (isTypeOfKind(type, TypeFlags.Boolean)) { return TypeReferenceSerializationKind.BooleanType; } - else if (allConstituentTypesHaveKind(type, TypeFlags.NumberLike)) { + else if (isTypeOfKind(type, TypeFlags.NumberLike)) { return TypeReferenceSerializationKind.NumberLikeType; } - else if (allConstituentTypesHaveKind(type, TypeFlags.StringLike)) { + else if (isTypeOfKind(type, TypeFlags.StringLike)) { return TypeReferenceSerializationKind.StringLikeType; } - else if (allConstituentTypesHaveKind(type, TypeFlags.Tuple)) { + else if (isTypeOfKind(type, TypeFlags.Tuple)) { return TypeReferenceSerializationKind.ArrayLikeType; } - else if (allConstituentTypesHaveKind(type, TypeFlags.ESSymbol)) { + else if (isTypeOfKind(type, TypeFlags.ESSymbol)) { return TypeReferenceSerializationKind.ESSymbolType; } else if (isFunctionType(type)) { From 45409982895306bf78e598604b7bc80ffa6f0ea8 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 6 Feb 2016 15:33:56 -0800 Subject: [PATCH 3/4] Adding test --- .../operatorsAndIntersectionTypes.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts diff --git a/tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts b/tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts new file mode 100644 index 0000000000000..5689d2218401a --- /dev/null +++ b/tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts @@ -0,0 +1,30 @@ +type Guid = string & { $Guid }; // Tagged string type +type SerialNo = number & { $SerialNo }; // Tagged number type + +function createGuid() { + return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid; +} + +function createSerialNo() { + return 12345 as SerialNo; +} + +let map1: { [x: string]: number } = {}; +let guid = createGuid(); +map1[guid] = 123; // Can with tagged string + +let map2: { [x: number]: string } = {}; +let serialNo = createSerialNo(); +map2[serialNo] = "hello"; // Can index with tagged number + +const s1 = "{" + guid + "}"; +const s2 = guid.toLowerCase(); +const s3 = guid + guid; +const s4 = guid + serialNo; +const s5 = serialNo.toPrecision(0); +const n1 = serialNo * 3; +const n2 = serialNo + serialNo; +const b1 = guid === ""; +const b2 = guid === guid; +const b3 = serialNo === 0; +const b4 = serialNo === serialNo; From 788ba3c6ac01141e264e4ccbf780ac624a46d928 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 6 Feb 2016 15:34:32 -0800 Subject: [PATCH 4/4] Accepting new baselines --- .../operatorsAndIntersectionTypes.js | 57 ++++++++ .../operatorsAndIntersectionTypes.symbols | 100 +++++++++++++ .../operatorsAndIntersectionTypes.types | 132 ++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 tests/baselines/reference/operatorsAndIntersectionTypes.js create mode 100644 tests/baselines/reference/operatorsAndIntersectionTypes.symbols create mode 100644 tests/baselines/reference/operatorsAndIntersectionTypes.types diff --git a/tests/baselines/reference/operatorsAndIntersectionTypes.js b/tests/baselines/reference/operatorsAndIntersectionTypes.js new file mode 100644 index 0000000000000..6f5b3d329d13c --- /dev/null +++ b/tests/baselines/reference/operatorsAndIntersectionTypes.js @@ -0,0 +1,57 @@ +//// [operatorsAndIntersectionTypes.ts] +type Guid = string & { $Guid }; // Tagged string type +type SerialNo = number & { $SerialNo }; // Tagged number type + +function createGuid() { + return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid; +} + +function createSerialNo() { + return 12345 as SerialNo; +} + +let map1: { [x: string]: number } = {}; +let guid = createGuid(); +map1[guid] = 123; // Can with tagged string + +let map2: { [x: number]: string } = {}; +let serialNo = createSerialNo(); +map2[serialNo] = "hello"; // Can index with tagged number + +const s1 = "{" + guid + "}"; +const s2 = guid.toLowerCase(); +const s3 = guid + guid; +const s4 = guid + serialNo; +const s5 = serialNo.toPrecision(0); +const n1 = serialNo * 3; +const n2 = serialNo + serialNo; +const b1 = guid === ""; +const b2 = guid === guid; +const b3 = serialNo === 0; +const b4 = serialNo === serialNo; + + +//// [operatorsAndIntersectionTypes.js] +function createGuid() { + return "21EC2020-3AEA-4069-A2DD-08002B30309D"; +} +function createSerialNo() { + return 12345; +} +var map1 = {}; +var guid = createGuid(); +map1[guid] = 123; // Can with tagged string +var map2 = {}; +var serialNo = createSerialNo(); +map2[serialNo] = "hello"; // Can index with tagged number +var s1 = "{" + guid + "}"; +var s2 = guid.toLowerCase(); +var s3 = guid + guid; +var s4 = guid + serialNo; +var s5 = serialNo.toPrecision(0); +var n1 = serialNo * 3; +var n2 = serialNo + serialNo; +var b1 = guid === ""; +var b2 = guid === guid; +var b3 = serialNo === 0; +var b4 = serialNo === serialNo; diff --git a/tests/baselines/reference/operatorsAndIntersectionTypes.symbols b/tests/baselines/reference/operatorsAndIntersectionTypes.symbols new file mode 100644 index 0000000000000..7ffc093e4afa2 --- /dev/null +++ b/tests/baselines/reference/operatorsAndIntersectionTypes.symbols @@ -0,0 +1,100 @@ +=== tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts === +type Guid = string & { $Guid }; // Tagged string type +>Guid : Symbol(Guid, Decl(operatorsAndIntersectionTypes.ts, 0, 0)) +>$Guid : Symbol($Guid, Decl(operatorsAndIntersectionTypes.ts, 0, 22)) + +type SerialNo = number & { $SerialNo }; // Tagged number type +>SerialNo : Symbol(SerialNo, Decl(operatorsAndIntersectionTypes.ts, 0, 31)) +>$SerialNo : Symbol($SerialNo, Decl(operatorsAndIntersectionTypes.ts, 1, 26)) + +function createGuid() { +>createGuid : Symbol(createGuid, Decl(operatorsAndIntersectionTypes.ts, 1, 39)) + + return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid; +>Guid : Symbol(Guid, Decl(operatorsAndIntersectionTypes.ts, 0, 0)) +} + +function createSerialNo() { +>createSerialNo : Symbol(createSerialNo, Decl(operatorsAndIntersectionTypes.ts, 5, 1)) + + return 12345 as SerialNo; +>SerialNo : Symbol(SerialNo, Decl(operatorsAndIntersectionTypes.ts, 0, 31)) +} + +let map1: { [x: string]: number } = {}; +>map1 : Symbol(map1, Decl(operatorsAndIntersectionTypes.ts, 11, 3)) +>x : Symbol(x, Decl(operatorsAndIntersectionTypes.ts, 11, 13)) + +let guid = createGuid(); +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) +>createGuid : Symbol(createGuid, Decl(operatorsAndIntersectionTypes.ts, 1, 39)) + +map1[guid] = 123; // Can with tagged string +>map1 : Symbol(map1, Decl(operatorsAndIntersectionTypes.ts, 11, 3)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) + +let map2: { [x: number]: string } = {}; +>map2 : Symbol(map2, Decl(operatorsAndIntersectionTypes.ts, 15, 3)) +>x : Symbol(x, Decl(operatorsAndIntersectionTypes.ts, 15, 13)) + +let serialNo = createSerialNo(); +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) +>createSerialNo : Symbol(createSerialNo, Decl(operatorsAndIntersectionTypes.ts, 5, 1)) + +map2[serialNo] = "hello"; // Can index with tagged number +>map2 : Symbol(map2, Decl(operatorsAndIntersectionTypes.ts, 15, 3)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) + +const s1 = "{" + guid + "}"; +>s1 : Symbol(s1, Decl(operatorsAndIntersectionTypes.ts, 19, 5)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) + +const s2 = guid.toLowerCase(); +>s2 : Symbol(s2, Decl(operatorsAndIntersectionTypes.ts, 20, 5)) +>guid.toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) +>toLowerCase : Symbol(String.toLowerCase, Decl(lib.d.ts, --, --)) + +const s3 = guid + guid; +>s3 : Symbol(s3, Decl(operatorsAndIntersectionTypes.ts, 21, 5)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) + +const s4 = guid + serialNo; +>s4 : Symbol(s4, Decl(operatorsAndIntersectionTypes.ts, 22, 5)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) + +const s5 = serialNo.toPrecision(0); +>s5 : Symbol(s5, Decl(operatorsAndIntersectionTypes.ts, 23, 5)) +>serialNo.toPrecision : Symbol(Number.toPrecision, Decl(lib.d.ts, --, --)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) +>toPrecision : Symbol(Number.toPrecision, Decl(lib.d.ts, --, --)) + +const n1 = serialNo * 3; +>n1 : Symbol(n1, Decl(operatorsAndIntersectionTypes.ts, 24, 5)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) + +const n2 = serialNo + serialNo; +>n2 : Symbol(n2, Decl(operatorsAndIntersectionTypes.ts, 25, 5)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) + +const b1 = guid === ""; +>b1 : Symbol(b1, Decl(operatorsAndIntersectionTypes.ts, 26, 5)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) + +const b2 = guid === guid; +>b2 : Symbol(b2, Decl(operatorsAndIntersectionTypes.ts, 27, 5)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) +>guid : Symbol(guid, Decl(operatorsAndIntersectionTypes.ts, 12, 3)) + +const b3 = serialNo === 0; +>b3 : Symbol(b3, Decl(operatorsAndIntersectionTypes.ts, 28, 5)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) + +const b4 = serialNo === serialNo; +>b4 : Symbol(b4, Decl(operatorsAndIntersectionTypes.ts, 29, 5)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) +>serialNo : Symbol(serialNo, Decl(operatorsAndIntersectionTypes.ts, 16, 3)) + diff --git a/tests/baselines/reference/operatorsAndIntersectionTypes.types b/tests/baselines/reference/operatorsAndIntersectionTypes.types new file mode 100644 index 0000000000000..70611776fc1cd --- /dev/null +++ b/tests/baselines/reference/operatorsAndIntersectionTypes.types @@ -0,0 +1,132 @@ +=== tests/cases/conformance/types/intersection/operatorsAndIntersectionTypes.ts === +type Guid = string & { $Guid }; // Tagged string type +>Guid : string & { $Guid: any; } +>$Guid : any + +type SerialNo = number & { $SerialNo }; // Tagged number type +>SerialNo : number & { $SerialNo: any; } +>$SerialNo : any + +function createGuid() { +>createGuid : () => string & { $Guid: any; } + + return "21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid; +>"21EC2020-3AEA-4069-A2DD-08002B30309D" as Guid : string & { $Guid: any; } +>"21EC2020-3AEA-4069-A2DD-08002B30309D" : string +>Guid : string & { $Guid: any; } +} + +function createSerialNo() { +>createSerialNo : () => number & { $SerialNo: any; } + + return 12345 as SerialNo; +>12345 as SerialNo : number & { $SerialNo: any; } +>12345 : number +>SerialNo : number & { $SerialNo: any; } +} + +let map1: { [x: string]: number } = {}; +>map1 : { [x: string]: number; } +>x : string +>{} : { [x: string]: undefined; } + +let guid = createGuid(); +>guid : string & { $Guid: any; } +>createGuid() : string & { $Guid: any; } +>createGuid : () => string & { $Guid: any; } + +map1[guid] = 123; // Can with tagged string +>map1[guid] = 123 : number +>map1[guid] : number +>map1 : { [x: string]: number; } +>guid : string & { $Guid: any; } +>123 : number + +let map2: { [x: number]: string } = {}; +>map2 : { [x: number]: string; } +>x : number +>{} : { [x: number]: undefined; } + +let serialNo = createSerialNo(); +>serialNo : number & { $SerialNo: any; } +>createSerialNo() : number & { $SerialNo: any; } +>createSerialNo : () => number & { $SerialNo: any; } + +map2[serialNo] = "hello"; // Can index with tagged number +>map2[serialNo] = "hello" : string +>map2[serialNo] : string +>map2 : { [x: number]: string; } +>serialNo : number & { $SerialNo: any; } +>"hello" : string + +const s1 = "{" + guid + "}"; +>s1 : string +>"{" + guid + "}" : string +>"{" + guid : string +>"{" : string +>guid : string & { $Guid: any; } +>"}" : string + +const s2 = guid.toLowerCase(); +>s2 : string +>guid.toLowerCase() : string +>guid.toLowerCase : () => string +>guid : string & { $Guid: any; } +>toLowerCase : () => string + +const s3 = guid + guid; +>s3 : string +>guid + guid : string +>guid : string & { $Guid: any; } +>guid : string & { $Guid: any; } + +const s4 = guid + serialNo; +>s4 : string +>guid + serialNo : string +>guid : string & { $Guid: any; } +>serialNo : number & { $SerialNo: any; } + +const s5 = serialNo.toPrecision(0); +>s5 : string +>serialNo.toPrecision(0) : string +>serialNo.toPrecision : (precision?: number) => string +>serialNo : number & { $SerialNo: any; } +>toPrecision : (precision?: number) => string +>0 : number + +const n1 = serialNo * 3; +>n1 : number +>serialNo * 3 : number +>serialNo : number & { $SerialNo: any; } +>3 : number + +const n2 = serialNo + serialNo; +>n2 : number +>serialNo + serialNo : number +>serialNo : number & { $SerialNo: any; } +>serialNo : number & { $SerialNo: any; } + +const b1 = guid === ""; +>b1 : boolean +>guid === "" : boolean +>guid : string & { $Guid: any; } +>"" : string + +const b2 = guid === guid; +>b2 : boolean +>guid === guid : boolean +>guid : string & { $Guid: any; } +>guid : string & { $Guid: any; } + +const b3 = serialNo === 0; +>b3 : boolean +>serialNo === 0 : boolean +>serialNo : number & { $SerialNo: any; } +>0 : number + +const b4 = serialNo === serialNo; +>b4 : boolean +>serialNo === serialNo : boolean +>serialNo : number & { $SerialNo: any; } +>serialNo : number & { $SerialNo: any; } +