From ec30c20ec975675fc4941c3a1236edff1f36bf5c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sat, 19 Jan 2019 10:25:41 -0800 Subject: [PATCH] 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 57f8d03776..bc4375413d 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 9d2f251e10..96c8854bff 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",