Skip to content

Commit ec30c20

Browse files
committed
Validate const assertion operand
1 parent beb0270 commit ec30c20

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

src/compiler/checker.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9104,7 +9104,7 @@ namespace ts {
91049104
function createTupleType(elementTypes: ReadonlyArray<Type>, minLength = elementTypes.length, hasRestElement = false, readonly = false, associatedNames?: __String[]) {
91059105
const arity = elementTypes.length;
91069106
if (arity === 1 && hasRestElement) {
9107-
return createArrayType(elementTypes[0]);
9107+
return createArrayType(elementTypes[0], readonly);
91089108
}
91099109
const tupleType = getTupleTypeOfArity(arity, minLength, arity > 0 && hasRestElement, readonly, associatedNames);
91109110
return elementTypes.length ? createTypeReference(tupleType, elementTypes) : tupleType;
@@ -21158,9 +21158,34 @@ namespace ts {
2115821158
return checkAssertionWorker(node, node.type, node.expression);
2115921159
}
2116021160

21161+
function isValidConstAssertionArgument(node: Node): boolean {
21162+
switch (node.kind) {
21163+
case SyntaxKind.StringLiteral:
21164+
case SyntaxKind.NoSubstitutionTemplateLiteral:
21165+
case SyntaxKind.NumericLiteral:
21166+
case SyntaxKind.BigIntLiteral:
21167+
case SyntaxKind.TrueKeyword:
21168+
case SyntaxKind.FalseKeyword:
21169+
case SyntaxKind.ArrayLiteralExpression:
21170+
case SyntaxKind.ObjectLiteralExpression:
21171+
return true;
21172+
case SyntaxKind.ParenthesizedExpression:
21173+
return isValidConstAssertionArgument((<ParenthesizedExpression>node).expression);
21174+
case SyntaxKind.PrefixUnaryExpression:
21175+
const op = (<PrefixUnaryExpression>node).operator;
21176+
const arg = (<PrefixUnaryExpression>node).operand;
21177+
return op === SyntaxKind.MinusToken && (arg.kind === SyntaxKind.NumericLiteral || arg.kind === SyntaxKind.BigIntLiteral) ||
21178+
op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral;
21179+
}
21180+
return false;
21181+
}
21182+
2116121183
function checkAssertionWorker(errNode: Node, type: TypeNode, expression: UnaryExpression | Expression, checkMode?: CheckMode) {
2116221184
let exprType = checkExpression(expression, checkMode);
2116321185
if (isConstTypeReference(type)) {
21186+
if (!isValidConstAssertionArgument(expression)) {
21187+
error(expression, Diagnostics.A_const_assertion_can_only_be_applied_to_a_string_number_boolean_array_or_object_literal);
21188+
}
2116421189
return getRegularTypeOfLiteralType(exprType);
2116521190
}
2116621191
checkSourceElement(type);

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,6 +1027,10 @@
10271027
"category": "Error",
10281028
"code": 1354
10291029
},
1030+
"A 'const' assertion can only be applied to a string, number, boolean, array, or object literal.": {
1031+
"category": "Error",
1032+
"code": 1355
1033+
},
10301034

10311035
"Duplicate identifier '{0}'.": {
10321036
"category": "Error",

0 commit comments

Comments
 (0)