From beb02703b818857ebc1db9f02f3b69e6a2c3d493 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Fri, 18 Jan 2019 16:16:45 -0800 Subject: [PATCH 1/5] Support ' xxx' and 'xxx as const' --- src/compiler/checker.ts | 101 +++++++++++++++++++++----------------- src/compiler/utilities.ts | 5 ++ 2 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c126b5458f196..57f8d03776280 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3788,7 +3788,7 @@ namespace ts { context.approximateLength += (symbolName(propertySymbol).length + 1); context.enclosingDeclaration = saveEnclosingDeclaration; const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined; - if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { + if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) { const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); for (const signature of signatures) { const methodDeclaration = signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context); @@ -4790,7 +4790,7 @@ namespace ts { if (!isTypeAssignableTo(getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique), omitKeyType) && !(getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected)) && isSpreadableProperty(prop)) { - members.set(prop.escapedName, getSpreadSymbol(prop)); + members.set(prop.escapedName, getSpreadSymbol(prop, /*readonly*/ false)); } } const stringIndexInfo = getIndexInfoOfType(source, IndexKind.String); @@ -10223,7 +10223,7 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, typeFlags: TypeFlags, objectFlags: ObjectFlags): Type { + function getSpreadType(left: Type, right: Type, symbol: Symbol | undefined, typeFlags: TypeFlags, objectFlags: ObjectFlags, readonly: boolean): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } @@ -10237,10 +10237,10 @@ namespace ts { return left; } if (left.flags & TypeFlags.Union) { - return mapType(left, t => getSpreadType(t, right, symbol, typeFlags, objectFlags)); + return mapType(left, t => getSpreadType(t, right, symbol, typeFlags, objectFlags, readonly)); } if (right.flags & TypeFlags.Union) { - return mapType(right, t => getSpreadType(left, t, symbol, typeFlags, objectFlags)); + return mapType(right, t => getSpreadType(left, t, symbol, typeFlags, objectFlags, readonly)); } if (right.flags & (TypeFlags.BooleanLike | TypeFlags.NumberLike | TypeFlags.BigIntLike | TypeFlags.StringLike | TypeFlags.EnumLike | TypeFlags.NonPrimitive | TypeFlags.Index)) { return left; @@ -10257,7 +10257,7 @@ namespace ts { const types = (left).types; const lastLeft = types[types.length - 1]; if (isNonGenericObjectType(lastLeft) && isNonGenericObjectType(right)) { - return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, typeFlags, objectFlags)])); + return getIntersectionType(concatenate(types.slice(0, types.length - 1), [getSpreadType(lastLeft, right, symbol, typeFlags, objectFlags, readonly)])); } } return getIntersectionType([left, right]); @@ -10282,7 +10282,7 @@ namespace ts { skippedPrivateMembers.set(rightProp.escapedName, true); } else if (isSpreadableProperty(rightProp)) { - members.set(rightProp.escapedName, getSpreadSymbol(rightProp)); + members.set(rightProp.escapedName, getSpreadSymbol(rightProp, readonly)); } } @@ -10306,7 +10306,7 @@ namespace ts { } } else { - members.set(leftProp.escapedName, getSpreadSymbol(leftProp)); + members.set(leftProp.escapedName, getSpreadSymbol(leftProp, readonly)); } } @@ -10315,8 +10315,8 @@ namespace ts { members, emptyArray, emptyArray, - getNonReadonlyIndexSignature(stringIndexInfo), - getNonReadonlyIndexSignature(numberIndexInfo)); + getIndexInfoWithReadonly(stringIndexInfo, readonly), + getIndexInfoWithReadonly(numberIndexInfo, readonly)); spread.flags |= TypeFlags.ContainsObjectLiteral | typeFlags; spread.objectFlags |= ObjectFlags.ObjectLiteral | ObjectFlags.ContainsSpread | objectFlags; return spread; @@ -10328,14 +10328,13 @@ namespace ts { !prop.declarations.some(decl => isClassLike(decl.parent)); } - function getSpreadSymbol(prop: Symbol) { - const isReadonly = isReadonlySymbol(prop); + function getSpreadSymbol(prop: Symbol, readonly: boolean) { const isSetonlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); - if (!isReadonly && !isSetonlyAccessor) { + if (!isSetonlyAccessor && readonly === isReadonlySymbol(prop)) { return prop; } const flags = SymbolFlags.Property | (prop.flags & SymbolFlags.Optional); - const result = createSymbol(flags, prop.escapedName); + const result = createSymbol(flags, prop.escapedName, readonly ? CheckFlags.Readonly : 0); result.type = isSetonlyAccessor ? undefinedType : getTypeOfSymbol(prop); result.declarations = prop.declarations; result.nameType = prop.nameType; @@ -10343,11 +10342,8 @@ namespace ts { return result; } - function getNonReadonlyIndexSignature(index: IndexInfo | undefined) { - if (index && index.isReadonly) { - return createIndexInfo(index.type, /*isReadonly*/ false, index.declaration); - } - return index; + function getIndexInfoWithReadonly(info: IndexInfo | undefined, readonly: boolean) { + return info && info.isReadonly !== readonly ? createIndexInfo(info.type, readonly, info.declaration) : info; } function createLiteralType(flags: TypeFlags, value: string | number | PseudoBigInt, symbol: Symbol | undefined) { @@ -17623,7 +17619,7 @@ namespace ts { return getContextualTypeForArgument(parent, node); case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: - return getTypeFromTypeNode((parent).type); + return isConstTypeReference((parent).type) ? undefined : getTypeFromTypeNode((parent).type); case SyntaxKind.BinaryExpression: return getContextualTypeForBinaryOperand(node); case SyntaxKind.PropertyAssignment: @@ -17909,6 +17905,7 @@ namespace ts { const elementTypes: Type[] = []; const inDestructuringPattern = isAssignmentTarget(node); const contextualType = getApparentTypeOfContextualType(node); + const inConstContext = isConstContext(node); for (let index = 0; index < elementCount; index++) { const e = elements[index]; if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElement) { @@ -17951,7 +17948,7 @@ namespace ts { type.pattern = node; return type; } - else if (tupleResult = getArrayLiteralTupleTypeIfApplicable(elementTypes, contextualType, hasRestElement, elementCount)) { + else if (tupleResult = getArrayLiteralTupleTypeIfApplicable(elementTypes, contextualType, hasRestElement, elementCount, inConstContext)) { return tupleResult; } else if (forceTuple) { @@ -17960,14 +17957,14 @@ namespace ts { } return createArrayType(elementTypes.length ? getUnionType(elementTypes, UnionReduction.Subtype) : - strictNullChecks ? implicitNeverType : undefinedWideningType); + strictNullChecks ? implicitNeverType : undefinedWideningType, inConstContext); } - function getArrayLiteralTupleTypeIfApplicable(elementTypes: Type[], contextualType: Type | undefined, hasRestElement: boolean, elementCount = elementTypes.length) { + function getArrayLiteralTupleTypeIfApplicable(elementTypes: Type[], contextualType: Type | undefined, hasRestElement: boolean, elementCount = elementTypes.length, readonly = false) { // Infer a tuple type when the contextual type is or contains a tuple-like type - if (contextualType && forEachType(contextualType, isTupleLikeType)) { + if (readonly || (contextualType && forEachType(contextualType, isTupleLikeType))) { const minLength = elementCount - (hasRestElement ? 1 : 0); - const pattern = contextualType.pattern; + const pattern = contextualType && contextualType.pattern; // If array literal is contextually typed by a binding pattern or an assignment pattern, pad the resulting // tuple type with the corresponding binding or assignment element types to make the lengths equal. if (!hasRestElement && pattern && (pattern.kind === SyntaxKind.ArrayBindingPattern || pattern.kind === SyntaxKind.ArrayLiteralExpression)) { @@ -17985,7 +17982,7 @@ namespace ts { } } } - return createTupleType(elementTypes, minLength, hasRestElement); + return createTupleType(elementTypes, minLength, hasRestElement, readonly); } } @@ -18057,15 +18054,15 @@ namespace ts { return links.resolvedType; } - function getObjectLiteralIndexInfo(propertyNodes: NodeArray, offset: number, properties: Symbol[], kind: IndexKind): IndexInfo { + function getObjectLiteralIndexInfo(node: ObjectLiteralExpression, offset: number, properties: Symbol[], kind: IndexKind): IndexInfo { const propTypes: Type[] = []; for (let i = 0; i < properties.length; i++) { - if (kind === IndexKind.String || isNumericName(propertyNodes[i + offset].name!)) { + if (kind === IndexKind.String || isNumericName(node.properties[i + offset].name!)) { propTypes.push(getTypeOfSymbol(properties[i])); } } const unionType = propTypes.length ? getUnionType(propTypes, UnionReduction.Subtype) : undefinedType; - return createIndexInfo(unionType, /*isReadonly*/ false); + return createIndexInfo(unionType, isConstContext(node)); } function getImmediateAliasedSymbol(symbol: Symbol): Symbol | undefined { @@ -18093,6 +18090,8 @@ namespace ts { const contextualType = getApparentTypeOfContextualType(node); const contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); + const inConstContext = isConstContext(node); + const checkFlags = inConstContext ? CheckFlags.Readonly : 0; const isInJavascript = isInJSFile(node) && !isInJsonFile(node); const enumTag = getJSDocEnumTag(node); const isJSObjectLiteral = !contextualType && isInJavascript && !enumTag; @@ -18128,8 +18127,8 @@ namespace ts { const nameType = computedNameType && computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique ? computedNameType : undefined; const prop = nameType ? - createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType), CheckFlags.Late) : - createSymbol(SymbolFlags.Property | member.flags, member.escapedName); + createSymbol(SymbolFlags.Property | member.flags, getLateBoundNameFromType(nameType), checkFlags | CheckFlags.Late) : + createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags); if (nameType) { prop.nameType = nameType; } @@ -18173,7 +18172,7 @@ namespace ts { checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign); } if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, ObjectFlags.FreshLiteral); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, ObjectFlags.FreshLiteral, inConstContext); propertiesArray = []; propertiesTable = createSymbolTable(); hasComputedStringProperty = false; @@ -18185,7 +18184,7 @@ namespace ts { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return errorType; } - spread = getSpreadType(spread, type, node.symbol, propagatedFlags, ObjectFlags.FreshLiteral); + spread = getSpreadType(spread, type, node.symbol, propagatedFlags, ObjectFlags.FreshLiteral, inConstContext); offset = i + 1; continue; } @@ -18235,7 +18234,7 @@ namespace ts { if (spread !== emptyObjectType) { if (propertiesArray.length > 0) { - spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, ObjectFlags.FreshLiteral); + spread = getSpreadType(spread, createObjectLiteralType(), node.symbol, propagatedFlags, ObjectFlags.FreshLiteral, inConstContext); } return spread; } @@ -18243,8 +18242,8 @@ namespace ts { return createObjectLiteralType(); function createObjectLiteralType() { - const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined; - const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined; + const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, offset, propertiesArray, IndexKind.String) : undefined; + const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, offset, propertiesArray, IndexKind.Number) : undefined; const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo); result.flags |= TypeFlags.ContainsObjectLiteral | typeFlags & TypeFlags.PropagatingFlags; result.objectFlags |= ObjectFlags.ObjectLiteral | freshObjectLiteralFlag; @@ -18374,7 +18373,7 @@ namespace ts { else { Debug.assert(attributeDecl.kind === SyntaxKind.JsxSpreadAttribute); if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, typeFlags, objectFlags); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, typeFlags, objectFlags, /*readonly*/ false); attributesTable = createSymbolTable(); } const exprType = checkExpressionCached(attributeDecl.expression, checkMode); @@ -18382,7 +18381,7 @@ namespace ts { hasSpreadAnyType = true; } if (isValidSpreadType(exprType)) { - spread = getSpreadType(spread, exprType, attributes.symbol, typeFlags, objectFlags); + spread = getSpreadType(spread, exprType, attributes.symbol, typeFlags, objectFlags, /*readonly*/ false); } else { typeToIntersect = typeToIntersect ? getIntersectionType([typeToIntersect, exprType]) : exprType; @@ -18392,7 +18391,7 @@ namespace ts { if (!hasSpreadAnyType) { if (attributesTable.size > 0) { - spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, typeFlags, objectFlags); + spread = getSpreadType(spread, createJsxAttributesType(), attributes.symbol, typeFlags, objectFlags, /*readonly*/ false); } } @@ -18420,7 +18419,7 @@ namespace ts { const childPropMap = createSymbolTable(); childPropMap.set(jsxChildrenPropertyName, childrenPropSymbol); spread = getSpreadType(spread, createAnonymousType(attributes.symbol, childPropMap, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined), - attributes.symbol, typeFlags, objectFlags); + attributes.symbol, typeFlags, objectFlags, /*readonly*/ false); } } @@ -21107,7 +21106,7 @@ namespace ts { const anonymousSymbol = createSymbol(SymbolFlags.TypeLiteral, InternalSymbolName.Type); const defaultContainingObject = createAnonymousType(anonymousSymbol, memberTable, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined); anonymousSymbol.type = defaultContainingObject; - synthType.syntheticType = isValidSpreadType(type) ? getSpreadType(type, defaultContainingObject, anonymousSymbol, /*typeFLags*/ 0, /*objectFlags*/ 0) : defaultContainingObject; + synthType.syntheticType = isValidSpreadType(type) ? getSpreadType(type, defaultContainingObject, anonymousSymbol, /*typeFLags*/ 0, /*objectFlags*/ 0, /*readonly*/ false) : defaultContainingObject; } else { synthType.syntheticType = type; @@ -21160,11 +21159,13 @@ namespace ts { } function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) { - const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(checkExpression(expression, checkMode))); - + let exprType = checkExpression(expression, checkMode); + if (isConstTypeReference(type)) { + return getRegularTypeOfLiteralType(exprType); + } checkSourceElement(type); + exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(exprType)); const targetType = getTypeFromTypeNode(type); - if (produceDiagnostics && targetType !== errorType) { const widenedType = getWidenedType(exprType); if (!isTypeComparableTo(targetType, widenedType)) { @@ -22884,12 +22885,20 @@ namespace ts { return false; } + function isConstContext(node: Expression): boolean { + const parent = node.parent; + return isAssertionExpression(parent) && isConstTypeReference(parent.type) || + (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) || + (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent)) && isConstContext(parent.parent); + } + function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type { if (arguments.length === 2) { contextualType = getContextualType(node); } const type = checkExpression(node, checkMode, forceTuple); - return isTypeAssertion(node) ? type : + return isConstContext(node) ? getRegularTypeOfLiteralType(type) : + isTypeAssertion(node) ? type : getWidenedLiteralLikeTypeForContextualType(type, contextualType); } @@ -22953,7 +22962,7 @@ namespace ts { return getReturnTypeOfSignature(signature); } } - else if (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) { + else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) { return getTypeFromTypeNode((expr).type); } // Otherwise simply call checkExpression. Ideally, the entire family of checkXXX functions diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9c6b27de13cce..1a352175cb82b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -5606,6 +5606,11 @@ namespace ts { return node.kind === SyntaxKind.TypeAssertionExpression; } + export function isConstTypeReference(node: Node) { + return isTypeReferenceNode(node) && isIdentifier(node.typeName) && + node.typeName.escapedText === "const" && !node.typeArguments; + } + export function isParenthesizedExpression(node: Node): node is ParenthesizedExpression { return node.kind === SyntaxKind.ParenthesizedExpression; } From ec30c20ec975675fc4941c3a1236edff1f36bf5c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Jan 2019 10:25:41 -0800 Subject: [PATCH 2/5] Validate const assertion operand --- src/compiler/checker.ts | 27 ++++++++++++++++++++++++++- src/compiler/diagnosticMessages.json | 4 ++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 57f8d03776280..bc4375413d7bf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9104,7 +9104,7 @@ namespace ts { function createTupleType(elementTypes: ReadonlyArray, minLength = elementTypes.length, hasRestElement = false, readonly = false, associatedNames?: __String[]) { const arity = elementTypes.length; if (arity === 1 && hasRestElement) { - return createArrayType(elementTypes[0]); + return createArrayType(elementTypes[0], readonly); } const tupleType = getTupleTypeOfArity(arity, minLength, arity > 0 && hasRestElement, readonly, associatedNames); return elementTypes.length ? createTypeReference(tupleType, elementTypes) : tupleType; @@ -21158,9 +21158,34 @@ namespace ts { return checkAssertionWorker(node, node.type, node.expression); } + function isValidConstAssertionArgument(node: Node): boolean { + switch (node.kind) { + case SyntaxKind.StringLiteral: + case SyntaxKind.NoSubstitutionTemplateLiteral: + case SyntaxKind.NumericLiteral: + case SyntaxKind.BigIntLiteral: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ObjectLiteralExpression: + return true; + case SyntaxKind.ParenthesizedExpression: + return isValidConstAssertionArgument((node).expression); + case SyntaxKind.PrefixUnaryExpression: + const op = (node).operator; + const arg = (node).operand; + return op === SyntaxKind.MinusToken && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) || + op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; + } + return false; + } + function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) { let exprType = checkExpression(expression, checkMode); if (isConstTypeReference(type)) { + if (!isValidConstAssertionArgument(expression)) { + error(expression, Diagnostics.A_const_assertion_can_only_be_applied_to_a_string_number_boolean_array_or_object_literal); + } return getRegularTypeOfLiteralType(exprType); } checkSourceElement(type); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9d2f251e10020..96c8854bff36c 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1027,6 +1027,10 @@ "category": "Error", "code": 1354 }, + "A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.": { + "category": "Error", + "code": 1355 + }, "Duplicate identifier '{0}'.": { "category": "Error", From 980a6817b3cd31594f0b08cf0e4d16cc3c80f075 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Jan 2019 10:34:29 -0800 Subject: [PATCH 3/5] Accept baseline API changes --- tests/baselines/reference/api/tsserverlibrary.d.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 380e43c2409ab..137e05303a758 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3355,6 +3355,7 @@ declare namespace ts { function isNewExpression(node: Node): node is NewExpression; function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression; function isTypeAssertion(node: Node): node is TypeAssertion; + function isConstTypeReference(node: Node): boolean; function isParenthesizedExpression(node: Node): node is ParenthesizedExpression; function skipPartiallyEmittedExpressions(node: Expression): Expression; function skipPartiallyEmittedExpressions(node: Node): Node; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 1234144ac4ab5..1debe817254cf 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3355,6 +3355,7 @@ declare namespace ts { function isNewExpression(node: Node): node is NewExpression; function isTaggedTemplateExpression(node: Node): node is TaggedTemplateExpression; function isTypeAssertion(node: Node): node is TypeAssertion; + function isConstTypeReference(node: Node): boolean; function isParenthesizedExpression(node: Node): node is ParenthesizedExpression; function skipPartiallyEmittedExpressions(node: Expression): Expression; function skipPartiallyEmittedExpressions(node: Node): Node; From 2e94f47602d970a60e78737f52cb0f9e21a13300 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Jan 2019 10:34:38 -0800 Subject: [PATCH 4/5] Add tests --- .../typeAssertions/constAssertions.ts | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/cases/conformance/expressions/typeAssertions/constAssertions.ts diff --git a/tests/cases/conformance/expressions/typeAssertions/constAssertions.ts b/tests/cases/conformance/expressions/typeAssertions/constAssertions.ts new file mode 100644 index 0000000000000..e2ce7aba9935c --- /dev/null +++ b/tests/cases/conformance/expressions/typeAssertions/constAssertions.ts @@ -0,0 +1,67 @@ +// @strict: true +// @declaration: true +// @target: esnext + +let v1 = 'abc' as const; +let v2 = `abc` as const; +let v3 = 10 as const; +let v4 = -10 as const; +let v5 = +10 as const; +let v6 = 10n as const; +let v7 = -10n as const; +let v8 = true as const; +let v9 = false as const; + +let c1 = 'abc' as const; +let c2 = `abc` as const; +let c3 = 10 as const; +let c4 = -10 as const; +let c5 = +10 as const; +let c6 = 10n as const; +let c7 = -10n as const; +let c8 = true as const; +let c9 = false as const; + +let vv1 = v1; +let vc1 = c1; + +let a1 = [] as const; +let a2 = [1, 2, 3] as const; +let a3 = [10, 'hello', true] as const; +let a4 = [...[1, 2, 3]] as const; +let a5 = [1, 2, 3]; +let a6 = [...a5] as const; +let a7 = [...a6]; +let a8 = ['abc', ...a7] as const; +let a9 = [...a8]; + +declare let d: { [x: string]: string }; + +let o1 = { x: 10, y: 20 } as const; +let o2 = { a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const; +let o3 = { ...o1, ...o2 } as const; +let o4 = { a: 1, b: 2 }; +let o5 = { ...o4 } as const; +let o6 = { ...o5 }; +let o7 = { ...d } as const; +let o8 = { ...o7 }; +let o9 = { x: 10, foo() { this.x = 20 } } as const; // Error + +let p1 = (10) as const; +let p2 = ((-10)) as const; +let p3 = ([(10)]) as const; +let p4 = [[[[10]]]] as const; + +let x1 = { x: 10, y: [20, 30], z: { a: { b: 42 } } } as const; + +let q1 = 10; +let q2 = 'abc'; +let q3 = true; +let q4 = [1, 2, 3]; +let q5 = { x: 10, y: 20 }; + +declare function id(x: T): T; + +let e1 = v1 as const; // Error +let e2 = (true ? 1 : 0) as const; // Error +let e3 = id(1) as const; // Error From dbfef5356c60fc28ff1e0ea829acd57fe59e0228 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Jan 2019 10:34:48 -0800 Subject: [PATCH 5/5] Accept baseline changes --- .../reference/constAssertions.errors.txt | 79 ++++ tests/baselines/reference/constAssertions.js | 220 +++++++++++ .../reference/constAssertions.symbols | 201 ++++++++++ .../baselines/reference/constAssertions.types | 356 ++++++++++++++++++ 4 files changed, 856 insertions(+) create mode 100644 tests/baselines/reference/constAssertions.errors.txt create mode 100644 tests/baselines/reference/constAssertions.js create mode 100644 tests/baselines/reference/constAssertions.symbols create mode 100644 tests/baselines/reference/constAssertions.types diff --git a/tests/baselines/reference/constAssertions.errors.txt b/tests/baselines/reference/constAssertions.errors.txt new file mode 100644 index 0000000000000..24fce1599012a --- /dev/null +++ b/tests/baselines/reference/constAssertions.errors.txt @@ -0,0 +1,79 @@ +tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(44,32): error TS2540: Cannot assign to 'x' because it is a read-only property. +tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(61,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal. +tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(62,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal. +tests/cases/conformance/expressions/typeAssertions/constAssertions.ts(63,10): error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal. + + +==== tests/cases/conformance/expressions/typeAssertions/constAssertions.ts (4 errors) ==== + let v1 = 'abc' as const; + let v2 = `abc` as const; + let v3 = 10 as const; + let v4 = -10 as const; + let v5 = +10 as const; + let v6 = 10n as const; + let v7 = -10n as const; + let v8 = true as const; + let v9 = false as const; + + let c1 = 'abc' as const; + let c2 = `abc` as const; + let c3 = 10 as const; + let c4 = -10 as const; + let c5 = +10 as const; + let c6 = 10n as const; + let c7 = -10n as const; + let c8 = true as const; + let c9 = false as const; + + let vv1 = v1; + let vc1 = c1; + + let a1 = [] as const; + let a2 = [1, 2, 3] as const; + let a3 = [10, 'hello', true] as const; + let a4 = [...[1, 2, 3]] as const; + let a5 = [1, 2, 3]; + let a6 = [...a5] as const; + let a7 = [...a6]; + let a8 = ['abc', ...a7] as const; + let a9 = [...a8]; + + declare let d: { [x: string]: string }; + + let o1 = { x: 10, y: 20 } as const; + let o2 = { a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const; + let o3 = { ...o1, ...o2 } as const; + let o4 = { a: 1, b: 2 }; + let o5 = { ...o4 } as const; + let o6 = { ...o5 }; + let o7 = { ...d } as const; + let o8 = { ...o7 }; + let o9 = { x: 10, foo() { this.x = 20 } } as const; // Error + ~ +!!! error TS2540: Cannot assign to 'x' because it is a read-only property. + + let p1 = (10) as const; + let p2 = ((-10)) as const; + let p3 = ([(10)]) as const; + let p4 = [[[[10]]]] as const; + + let x1 = { x: 10, y: [20, 30], z: { a: { b: 42 } } } as const; + + let q1 = 10; + let q2 = 'abc'; + let q3 = true; + let q4 = [1, 2, 3]; + let q5 = { x: 10, y: 20 }; + + declare function id(x: T): T; + + let e1 = v1 as const; // Error + ~~ +!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal. + let e2 = (true ? 1 : 0) as const; // Error + ~~~~~~~~~~~~~~ +!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal. + let e3 = id(1) as const; // Error + ~~~~~ +!!! error TS1355: A 'const' assertion can only be applied to a string, number, boolean, array, or object literal. + \ No newline at end of file diff --git a/tests/baselines/reference/constAssertions.js b/tests/baselines/reference/constAssertions.js new file mode 100644 index 0000000000000..9f173987d226e --- /dev/null +++ b/tests/baselines/reference/constAssertions.js @@ -0,0 +1,220 @@ +//// [constAssertions.ts] +let v1 = 'abc' as const; +let v2 = `abc` as const; +let v3 = 10 as const; +let v4 = -10 as const; +let v5 = +10 as const; +let v6 = 10n as const; +let v7 = -10n as const; +let v8 = true as const; +let v9 = false as const; + +let c1 = 'abc' as const; +let c2 = `abc` as const; +let c3 = 10 as const; +let c4 = -10 as const; +let c5 = +10 as const; +let c6 = 10n as const; +let c7 = -10n as const; +let c8 = true as const; +let c9 = false as const; + +let vv1 = v1; +let vc1 = c1; + +let a1 = [] as const; +let a2 = [1, 2, 3] as const; +let a3 = [10, 'hello', true] as const; +let a4 = [...[1, 2, 3]] as const; +let a5 = [1, 2, 3]; +let a6 = [...a5] as const; +let a7 = [...a6]; +let a8 = ['abc', ...a7] as const; +let a9 = [...a8]; + +declare let d: { [x: string]: string }; + +let o1 = { x: 10, y: 20 } as const; +let o2 = { a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const; +let o3 = { ...o1, ...o2 } as const; +let o4 = { a: 1, b: 2 }; +let o5 = { ...o4 } as const; +let o6 = { ...o5 }; +let o7 = { ...d } as const; +let o8 = { ...o7 }; +let o9 = { x: 10, foo() { this.x = 20 } } as const; // Error + +let p1 = (10) as const; +let p2 = ((-10)) as const; +let p3 = ([(10)]) as const; +let p4 = [[[[10]]]] as const; + +let x1 = { x: 10, y: [20, 30], z: { a: { b: 42 } } } as const; + +let q1 = 10; +let q2 = 'abc'; +let q3 = true; +let q4 = [1, 2, 3]; +let q5 = { x: 10, y: 20 }; + +declare function id(x: T): T; + +let e1 = v1 as const; // Error +let e2 = (true ? 1 : 0) as const; // Error +let e3 = id(1) as const; // Error + + +//// [constAssertions.js] +"use strict"; +let v1 = 'abc'; +let v2 = `abc`; +let v3 = 10; +let v4 = -10; +let v5 = +10; +let v6 = 10n; +let v7 = -10n; +let v8 = true; +let v9 = false; +let c1 = 'abc'; +let c2 = `abc`; +let c3 = 10; +let c4 = -10; +let c5 = +10; +let c6 = 10n; +let c7 = -10n; +let c8 = true; +let c9 = false; +let vv1 = v1; +let vc1 = c1; +let a1 = []; +let a2 = [1, 2, 3]; +let a3 = [10, 'hello', true]; +let a4 = [...[1, 2, 3]]; +let a5 = [1, 2, 3]; +let a6 = [...a5]; +let a7 = [...a6]; +let a8 = ['abc', ...a7]; +let a9 = [...a8]; +let o1 = { x: 10, y: 20 }; +let o2 = { a: 1, 'b': 2, ['c']: 3, d() { }, ['e' + '']: 4 }; +let o3 = { ...o1, ...o2 }; +let o4 = { a: 1, b: 2 }; +let o5 = { ...o4 }; +let o6 = { ...o5 }; +let o7 = { ...d }; +let o8 = { ...o7 }; +let o9 = { x: 10, foo() { this.x = 20; } }; // Error +let p1 = (10); +let p2 = ((-10)); +let p3 = ([(10)]); +let p4 = [[[[10]]]]; +let x1 = { x: 10, y: [20, 30], z: { a: { b: 42 } } }; +let q1 = 10; +let q2 = 'abc'; +let q3 = true; +let q4 = [1, 2, 3]; +let q5 = { x: 10, y: 20 }; +let e1 = v1; // Error +let e2 = (true ? 1 : 0); // Error +let e3 = id(1); // Error + + +//// [constAssertions.d.ts] +declare let v1: "abc"; +declare let v2: "abc"; +declare let v3: 10; +declare let v4: -10; +declare let v5: 10; +declare let v6: 10n; +declare let v7: -10n; +declare let v8: true; +declare let v9: false; +declare let c1: "abc"; +declare let c2: "abc"; +declare let c3: 10; +declare let c4: -10; +declare let c5: 10; +declare let c6: 10n; +declare let c7: -10n; +declare let c8: true; +declare let c9: false; +declare let vv1: "abc"; +declare let vc1: "abc"; +declare let a1: readonly []; +declare let a2: readonly [1, 2, 3]; +declare let a3: readonly [10, "hello", true]; +declare let a4: readonly (1 | 2 | 3)[]; +declare let a5: number[]; +declare let a6: readonly number[]; +declare let a7: number[]; +declare let a8: readonly ["abc", ...number[]]; +declare let a9: (number | "abc")[]; +declare let d: { + [x: string]: string; +}; +declare let o1: { + readonly x: 10; + readonly y: 20; +}; +declare let o2: { + readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; + readonly a: 1; + readonly 'b': 2; + readonly ['c']: 3; + readonly d: () => void; +}; +declare let o3: { + readonly a: 1; + readonly 'b': 2; + readonly ['c']: 3; + readonly d: () => void; + readonly x: 10; + readonly y: 20; +}; +declare let o4: { + a: number; + b: number; +}; +declare let o5: { + readonly a: number; + readonly b: number; +}; +declare let o6: { + a: number; + b: number; +}; +declare let o7: { + readonly [x: string]: string; +}; +declare let o8: { + [x: string]: string; +}; +declare let o9: { + readonly x: 10; + readonly foo: () => void; +}; +declare let p1: 10; +declare let p2: -10; +declare let p3: readonly [10]; +declare let p4: readonly [readonly [readonly [readonly [10]]]]; +declare let x1: { + readonly x: 10; + readonly y: readonly [20, 30]; + z: { + a: { + readonly b: 42; + }; + }; +}; +declare let q1: 10; +declare let q2: "abc"; +declare let q3: true; +declare let q4: readonly [1, 2, 3]; +declare let q5: { + readonly x: 10; + readonly y: 20; +}; +declare function id(x: T): T; +declare let e1: "abc"; +declare let e2: 0 | 1; +declare let e3: 1; diff --git a/tests/baselines/reference/constAssertions.symbols b/tests/baselines/reference/constAssertions.symbols new file mode 100644 index 0000000000000..598210f42b396 --- /dev/null +++ b/tests/baselines/reference/constAssertions.symbols @@ -0,0 +1,201 @@ +=== tests/cases/conformance/expressions/typeAssertions/constAssertions.ts === +let v1 = 'abc' as const; +>v1 : Symbol(v1, Decl(constAssertions.ts, 0, 3)) + +let v2 = `abc` as const; +>v2 : Symbol(v2, Decl(constAssertions.ts, 1, 3)) + +let v3 = 10 as const; +>v3 : Symbol(v3, Decl(constAssertions.ts, 2, 3)) + +let v4 = -10 as const; +>v4 : Symbol(v4, Decl(constAssertions.ts, 3, 3)) + +let v5 = +10 as const; +>v5 : Symbol(v5, Decl(constAssertions.ts, 4, 3)) + +let v6 = 10n as const; +>v6 : Symbol(v6, Decl(constAssertions.ts, 5, 3)) + +let v7 = -10n as const; +>v7 : Symbol(v7, Decl(constAssertions.ts, 6, 3)) + +let v8 = true as const; +>v8 : Symbol(v8, Decl(constAssertions.ts, 7, 3)) + +let v9 = false as const; +>v9 : Symbol(v9, Decl(constAssertions.ts, 8, 3)) + +let c1 = 'abc' as const; +>c1 : Symbol(c1, Decl(constAssertions.ts, 10, 3)) + +let c2 = `abc` as const; +>c2 : Symbol(c2, Decl(constAssertions.ts, 11, 3)) + +let c3 = 10 as const; +>c3 : Symbol(c3, Decl(constAssertions.ts, 12, 3)) + +let c4 = -10 as const; +>c4 : Symbol(c4, Decl(constAssertions.ts, 13, 3)) + +let c5 = +10 as const; +>c5 : Symbol(c5, Decl(constAssertions.ts, 14, 3)) + +let c6 = 10n as const; +>c6 : Symbol(c6, Decl(constAssertions.ts, 15, 3)) + +let c7 = -10n as const; +>c7 : Symbol(c7, Decl(constAssertions.ts, 16, 3)) + +let c8 = true as const; +>c8 : Symbol(c8, Decl(constAssertions.ts, 17, 3)) + +let c9 = false as const; +>c9 : Symbol(c9, Decl(constAssertions.ts, 18, 3)) + +let vv1 = v1; +>vv1 : Symbol(vv1, Decl(constAssertions.ts, 20, 3)) +>v1 : Symbol(v1, Decl(constAssertions.ts, 0, 3)) + +let vc1 = c1; +>vc1 : Symbol(vc1, Decl(constAssertions.ts, 21, 3)) +>c1 : Symbol(c1, Decl(constAssertions.ts, 10, 3)) + +let a1 = [] as const; +>a1 : Symbol(a1, Decl(constAssertions.ts, 23, 3)) + +let a2 = [1, 2, 3] as const; +>a2 : Symbol(a2, Decl(constAssertions.ts, 24, 3)) + +let a3 = [10, 'hello', true] as const; +>a3 : Symbol(a3, Decl(constAssertions.ts, 25, 3)) + +let a4 = [...[1, 2, 3]] as const; +>a4 : Symbol(a4, Decl(constAssertions.ts, 26, 3)) + +let a5 = [1, 2, 3]; +>a5 : Symbol(a5, Decl(constAssertions.ts, 27, 3)) + +let a6 = [...a5] as const; +>a6 : Symbol(a6, Decl(constAssertions.ts, 28, 3)) +>a5 : Symbol(a5, Decl(constAssertions.ts, 27, 3)) + +let a7 = [...a6]; +>a7 : Symbol(a7, Decl(constAssertions.ts, 29, 3)) +>a6 : Symbol(a6, Decl(constAssertions.ts, 28, 3)) + +let a8 = ['abc', ...a7] as const; +>a8 : Symbol(a8, Decl(constAssertions.ts, 30, 3)) +>a7 : Symbol(a7, Decl(constAssertions.ts, 29, 3)) + +let a9 = [...a8]; +>a9 : Symbol(a9, Decl(constAssertions.ts, 31, 3)) +>a8 : Symbol(a8, Decl(constAssertions.ts, 30, 3)) + +declare let d: { [x: string]: string }; +>d : Symbol(d, Decl(constAssertions.ts, 33, 11)) +>x : Symbol(x, Decl(constAssertions.ts, 33, 18)) + +let o1 = { x: 10, y: 20 } as const; +>o1 : Symbol(o1, Decl(constAssertions.ts, 35, 3)) +>x : Symbol(x, Decl(constAssertions.ts, 35, 10)) +>y : Symbol(y, Decl(constAssertions.ts, 35, 17)) + +let o2 = { a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const; +>o2 : Symbol(o2, Decl(constAssertions.ts, 36, 3)) +>a : Symbol(a, Decl(constAssertions.ts, 36, 10)) +>'b' : Symbol('b', Decl(constAssertions.ts, 36, 16)) +>['c'] : Symbol(['c'], Decl(constAssertions.ts, 36, 24)) +>'c' : Symbol(['c'], Decl(constAssertions.ts, 36, 24)) +>d : Symbol(d, Decl(constAssertions.ts, 36, 34)) +>['e' + ''] : Symbol(['e' + ''], Decl(constAssertions.ts, 36, 42)) + +let o3 = { ...o1, ...o2 } as const; +>o3 : Symbol(o3, Decl(constAssertions.ts, 37, 3)) +>o1 : Symbol(o1, Decl(constAssertions.ts, 35, 3)) +>o2 : Symbol(o2, Decl(constAssertions.ts, 36, 3)) + +let o4 = { a: 1, b: 2 }; +>o4 : Symbol(o4, Decl(constAssertions.ts, 38, 3)) +>a : Symbol(a, Decl(constAssertions.ts, 38, 10)) +>b : Symbol(b, Decl(constAssertions.ts, 38, 16)) + +let o5 = { ...o4 } as const; +>o5 : Symbol(o5, Decl(constAssertions.ts, 39, 3)) +>o4 : Symbol(o4, Decl(constAssertions.ts, 38, 3)) + +let o6 = { ...o5 }; +>o6 : Symbol(o6, Decl(constAssertions.ts, 40, 3)) +>o5 : Symbol(o5, Decl(constAssertions.ts, 39, 3)) + +let o7 = { ...d } as const; +>o7 : Symbol(o7, Decl(constAssertions.ts, 41, 3)) +>d : Symbol(d, Decl(constAssertions.ts, 33, 11)) + +let o8 = { ...o7 }; +>o8 : Symbol(o8, Decl(constAssertions.ts, 42, 3)) +>o7 : Symbol(o7, Decl(constAssertions.ts, 41, 3)) + +let o9 = { x: 10, foo() { this.x = 20 } } as const; // Error +>o9 : Symbol(o9, Decl(constAssertions.ts, 43, 3)) +>x : Symbol(x, Decl(constAssertions.ts, 43, 10)) +>foo : Symbol(foo, Decl(constAssertions.ts, 43, 17)) +>this.x : Symbol(x, Decl(constAssertions.ts, 43, 10)) +>this : Symbol(__object, Decl(constAssertions.ts, 43, 8)) +>x : Symbol(x, Decl(constAssertions.ts, 43, 10)) + +let p1 = (10) as const; +>p1 : Symbol(p1, Decl(constAssertions.ts, 45, 3)) + +let p2 = ((-10)) as const; +>p2 : Symbol(p2, Decl(constAssertions.ts, 46, 3)) + +let p3 = ([(10)]) as const; +>p3 : Symbol(p3, Decl(constAssertions.ts, 47, 3)) + +let p4 = [[[[10]]]] as const; +>p4 : Symbol(p4, Decl(constAssertions.ts, 48, 3)) + +let x1 = { x: 10, y: [20, 30], z: { a: { b: 42 } } } as const; +>x1 : Symbol(x1, Decl(constAssertions.ts, 50, 3)) +>x : Symbol(x, Decl(constAssertions.ts, 50, 10)) +>y : Symbol(y, Decl(constAssertions.ts, 50, 17)) +>z : Symbol(z, Decl(constAssertions.ts, 50, 30)) +>a : Symbol(a, Decl(constAssertions.ts, 50, 35)) +>b : Symbol(b, Decl(constAssertions.ts, 50, 40)) + +let q1 = 10; +>q1 : Symbol(q1, Decl(constAssertions.ts, 52, 3)) + +let q2 = 'abc'; +>q2 : Symbol(q2, Decl(constAssertions.ts, 53, 3)) + +let q3 = true; +>q3 : Symbol(q3, Decl(constAssertions.ts, 54, 3)) + +let q4 = [1, 2, 3]; +>q4 : Symbol(q4, Decl(constAssertions.ts, 55, 3)) + +let q5 = { x: 10, y: 20 }; +>q5 : Symbol(q5, Decl(constAssertions.ts, 56, 3)) +>x : Symbol(x, Decl(constAssertions.ts, 56, 18)) +>y : Symbol(y, Decl(constAssertions.ts, 56, 25)) + +declare function id(x: T): T; +>id : Symbol(id, Decl(constAssertions.ts, 56, 34)) +>T : Symbol(T, Decl(constAssertions.ts, 58, 20)) +>x : Symbol(x, Decl(constAssertions.ts, 58, 23)) +>T : Symbol(T, Decl(constAssertions.ts, 58, 20)) +>T : Symbol(T, Decl(constAssertions.ts, 58, 20)) + +let e1 = v1 as const; // Error +>e1 : Symbol(e1, Decl(constAssertions.ts, 60, 3)) +>v1 : Symbol(v1, Decl(constAssertions.ts, 0, 3)) + +let e2 = (true ? 1 : 0) as const; // Error +>e2 : Symbol(e2, Decl(constAssertions.ts, 61, 3)) + +let e3 = id(1) as const; // Error +>e3 : Symbol(e3, Decl(constAssertions.ts, 62, 3)) +>id : Symbol(id, Decl(constAssertions.ts, 56, 34)) + diff --git a/tests/baselines/reference/constAssertions.types b/tests/baselines/reference/constAssertions.types new file mode 100644 index 0000000000000..b1f90df15f06d --- /dev/null +++ b/tests/baselines/reference/constAssertions.types @@ -0,0 +1,356 @@ +=== tests/cases/conformance/expressions/typeAssertions/constAssertions.ts === +let v1 = 'abc' as const; +>v1 : "abc" +>'abc' as const : "abc" +>'abc' : "abc" + +let v2 = `abc` as const; +>v2 : "abc" +>`abc` as const : "abc" +>`abc` : "abc" + +let v3 = 10 as const; +>v3 : 10 +>10 as const : 10 +>10 : 10 + +let v4 = -10 as const; +>v4 : -10 +>-10 as const : -10 +>-10 : -10 +>10 : 10 + +let v5 = +10 as const; +>v5 : 10 +>+10 as const : 10 +>+10 : 10 +>10 : 10 + +let v6 = 10n as const; +>v6 : 10n +>10n as const : 10n +>10n : 10n + +let v7 = -10n as const; +>v7 : -10n +>-10n as const : -10n +>-10n : -10n +>10n : 10n + +let v8 = true as const; +>v8 : true +>true as const : true +>true : true + +let v9 = false as const; +>v9 : false +>false as const : false +>false : false + +let c1 = 'abc' as const; +>c1 : "abc" +>'abc' as const : "abc" +>'abc' : "abc" + +let c2 = `abc` as const; +>c2 : "abc" +>`abc` as const : "abc" +>`abc` : "abc" + +let c3 = 10 as const; +>c3 : 10 +>10 as const : 10 +>10 : 10 + +let c4 = -10 as const; +>c4 : -10 +>-10 as const : -10 +>-10 : -10 +>10 : 10 + +let c5 = +10 as const; +>c5 : 10 +>+10 as const : 10 +>+10 : 10 +>10 : 10 + +let c6 = 10n as const; +>c6 : 10n +>10n as const : 10n +>10n : 10n + +let c7 = -10n as const; +>c7 : -10n +>-10n as const : -10n +>-10n : -10n +>10n : 10n + +let c8 = true as const; +>c8 : true +>true as const : true +>true : true + +let c9 = false as const; +>c9 : false +>false as const : false +>false : false + +let vv1 = v1; +>vv1 : "abc" +>v1 : "abc" + +let vc1 = c1; +>vc1 : "abc" +>c1 : "abc" + +let a1 = [] as const; +>a1 : readonly [] +>[] as const : readonly [] +>[] : readonly [] + +let a2 = [1, 2, 3] as const; +>a2 : readonly [1, 2, 3] +>[1, 2, 3] as const : readonly [1, 2, 3] +>[1, 2, 3] : readonly [1, 2, 3] +>1 : 1 +>2 : 2 +>3 : 3 + +let a3 = [10, 'hello', true] as const; +>a3 : readonly [10, "hello", true] +>[10, 'hello', true] as const : readonly [10, "hello", true] +>[10, 'hello', true] : readonly [10, "hello", true] +>10 : 10 +>'hello' : "hello" +>true : true + +let a4 = [...[1, 2, 3]] as const; +>a4 : readonly (1 | 2 | 3)[] +>[...[1, 2, 3]] as const : readonly (1 | 2 | 3)[] +>[...[1, 2, 3]] : readonly (1 | 2 | 3)[] +>...[1, 2, 3] : 1 | 2 | 3 +>[1, 2, 3] : readonly [1, 2, 3] +>1 : 1 +>2 : 2 +>3 : 3 + +let a5 = [1, 2, 3]; +>a5 : number[] +>[1, 2, 3] : number[] +>1 : 1 +>2 : 2 +>3 : 3 + +let a6 = [...a5] as const; +>a6 : readonly number[] +>[...a5] as const : readonly number[] +>[...a5] : readonly number[] +>...a5 : number +>a5 : number[] + +let a7 = [...a6]; +>a7 : number[] +>[...a6] : number[] +>...a6 : number +>a6 : readonly number[] + +let a8 = ['abc', ...a7] as const; +>a8 : readonly ["abc", ...number[]] +>['abc', ...a7] as const : readonly ["abc", ...number[]] +>['abc', ...a7] : readonly ["abc", ...number[]] +>'abc' : "abc" +>...a7 : number +>a7 : number[] + +let a9 = [...a8]; +>a9 : (number | "abc")[] +>[...a8] : (number | "abc")[] +>...a8 : number | "abc" +>a8 : readonly ["abc", ...number[]] + +declare let d: { [x: string]: string }; +>d : { [x: string]: string; } +>x : string + +let o1 = { x: 10, y: 20 } as const; +>o1 : { readonly x: 10; readonly y: 20; } +>{ x: 10, y: 20 } as const : { readonly x: 10; readonly y: 20; } +>{ x: 10, y: 20 } : { readonly x: 10; readonly y: 20; } +>x : 10 +>10 : 10 +>y : 20 +>20 : 20 + +let o2 = { a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const; +>o2 : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly 'b': 2; readonly ['c']: 3; readonly d: () => void; } +>{ a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } as const : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly 'b': 2; readonly ['c']: 3; readonly d: () => void; } +>{ a: 1, 'b': 2, ['c']: 3, d() {}, ['e' + '']: 4 } : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly 'b': 2; readonly ['c']: 3; readonly d: () => void; } +>a : 1 +>1 : 1 +>'b' : 2 +>2 : 2 +>['c'] : 3 +>'c' : "c" +>3 : 3 +>d : () => void +>['e' + ''] : 4 +>'e' + '' : string +>'e' : "e" +>'' : "" +>4 : 4 + +let o3 = { ...o1, ...o2 } as const; +>o3 : { readonly a: 1; readonly 'b': 2; readonly ['c']: 3; readonly d: () => void; readonly x: 10; readonly y: 20; } +>{ ...o1, ...o2 } as const : { readonly a: 1; readonly 'b': 2; readonly ['c']: 3; readonly d: () => void; readonly x: 10; readonly y: 20; } +>{ ...o1, ...o2 } : { readonly a: 1; readonly 'b': 2; readonly ['c']: 3; readonly d: () => void; readonly x: 10; readonly y: 20; } +>o1 : { readonly x: 10; readonly y: 20; } +>o2 : { readonly [x: string]: 1 | 2 | 3 | (() => void) | 4; readonly a: 1; readonly 'b': 2; readonly ['c']: 3; readonly d: () => void; } + +let o4 = { a: 1, b: 2 }; +>o4 : { a: number; b: number; } +>{ a: 1, b: 2 } : { a: number; b: number; } +>a : number +>1 : 1 +>b : number +>2 : 2 + +let o5 = { ...o4 } as const; +>o5 : { readonly a: number; readonly b: number; } +>{ ...o4 } as const : { readonly a: number; readonly b: number; } +>{ ...o4 } : { readonly a: number; readonly b: number; } +>o4 : { a: number; b: number; } + +let o6 = { ...o5 }; +>o6 : { a: number; b: number; } +>{ ...o5 } : { a: number; b: number; } +>o5 : { readonly a: number; readonly b: number; } + +let o7 = { ...d } as const; +>o7 : { readonly [x: string]: string; } +>{ ...d } as const : { readonly [x: string]: string; } +>{ ...d } : { readonly [x: string]: string; } +>d : { [x: string]: string; } + +let o8 = { ...o7 }; +>o8 : { [x: string]: string; } +>{ ...o7 } : { [x: string]: string; } +>o7 : { readonly [x: string]: string; } + +let o9 = { x: 10, foo() { this.x = 20 } } as const; // Error +>o9 : { readonly x: 10; readonly foo: () => void; } +>{ x: 10, foo() { this.x = 20 } } as const : { readonly x: 10; readonly foo: () => void; } +>{ x: 10, foo() { this.x = 20 } } : { readonly x: 10; readonly foo: () => void; } +>x : 10 +>10 : 10 +>foo : () => void +>this.x = 20 : 20 +>this.x : any +>this : { readonly x: 10; readonly foo: () => void; } +>x : any +>20 : 20 + +let p1 = (10) as const; +>p1 : 10 +>(10) as const : 10 +>(10) : 10 +>10 : 10 + +let p2 = ((-10)) as const; +>p2 : -10 +>((-10)) as const : -10 +>((-10)) : -10 +>(-10) : -10 +>-10 : -10 +>10 : 10 + +let p3 = ([(10)]) as const; +>p3 : readonly [10] +>([(10)]) as const : readonly [10] +>([(10)]) : readonly [10] +>[(10)] : readonly [10] +>(10) : 10 +>10 : 10 + +let p4 = [[[[10]]]] as const; +>p4 : readonly [readonly [readonly [readonly [10]]]] +>[[[[10]]]] as const : readonly [readonly [readonly [readonly [10]]]] +>[[[[10]]]] : readonly [readonly [readonly [readonly [10]]]] +>[[[10]]] : readonly [readonly [readonly [10]]] +>[[10]] : readonly [readonly [10]] +>[10] : readonly [10] +>10 : 10 + +let x1 = { x: 10, y: [20, 30], z: { a: { b: 42 } } } as const; +>x1 : { readonly x: 10; readonly y: readonly [20, 30]; z: { a: { readonly b: 42; }; }; } +>{ x: 10, y: [20, 30], z: { a: { b: 42 } } } as const : { readonly x: 10; readonly y: readonly [20, 30]; readonly z: { readonly a: { readonly b: 42; }; }; } +>{ x: 10, y: [20, 30], z: { a: { b: 42 } } } : { readonly x: 10; readonly y: readonly [20, 30]; readonly z: { readonly a: { readonly b: 42; }; }; } +>x : 10 +>10 : 10 +>y : readonly [20, 30] +>[20, 30] : readonly [20, 30] +>20 : 20 +>30 : 30 +>z : { readonly a: { readonly b: 42; }; } +>{ a: { b: 42 } } : { readonly a: { readonly b: 42; }; } +>a : { readonly b: 42; } +>{ b: 42 } : { readonly b: 42; } +>b : 42 +>42 : 42 + +let q1 = 10; +>q1 : 10 +> 10 : 10 +>10 : 10 + +let q2 = 'abc'; +>q2 : "abc" +> 'abc' : "abc" +>'abc' : "abc" + +let q3 = true; +>q3 : true +> true : true +>true : true + +let q4 = [1, 2, 3]; +>q4 : readonly [1, 2, 3] +> [1, 2, 3] : readonly [1, 2, 3] +>[1, 2, 3] : readonly [1, 2, 3] +>1 : 1 +>2 : 2 +>3 : 3 + +let q5 = { x: 10, y: 20 }; +>q5 : { readonly x: 10; readonly y: 20; } +> { x: 10, y: 20 } : { readonly x: 10; readonly y: 20; } +>{ x: 10, y: 20 } : { readonly x: 10; readonly y: 20; } +>x : 10 +>10 : 10 +>y : 20 +>20 : 20 + +declare function id(x: T): T; +>id : (x: T) => T +>x : T + +let e1 = v1 as const; // Error +>e1 : "abc" +>v1 as const : "abc" +>v1 : "abc" + +let e2 = (true ? 1 : 0) as const; // Error +>e2 : 0 | 1 +>(true ? 1 : 0) as const : 0 | 1 +>(true ? 1 : 0) : 0 | 1 +>true ? 1 : 0 : 0 | 1 +>true : true +>1 : 1 +>0 : 0 + +let e3 = id(1) as const; // Error +>e3 : 1 +>id(1) as const : 1 +>id(1) : 1 +>id : (x: T) => T +>1 : 1 +