Merge pull request #29510 from Microsoft/constContexts

Const contexts for literal expressions
This commit is contained in:
Anders Hejlsberg 2019-01-30 15:55:47 -08:00 committed by GitHub
commit 96706a75ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1015 additions and 47 deletions

View file

@ -3789,7 +3789,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 = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature, context);
@ -4791,7 +4791,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);
@ -9124,7 +9124,7 @@ namespace ts {
function createTupleType(elementTypes: ReadonlyArray<Type>, 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;
@ -10258,7 +10258,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;
}
@ -10272,10 +10272,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;
@ -10292,7 +10292,7 @@ namespace ts {
const types = (<IntersectionType>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]);
@ -10317,7 +10317,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));
}
}
@ -10341,7 +10341,7 @@ namespace ts {
}
}
else {
members.set(leftProp.escapedName, getSpreadSymbol(leftProp));
members.set(leftProp.escapedName, getSpreadSymbol(leftProp, readonly));
}
}
@ -10350,8 +10350,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;
@ -10363,14 +10363,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;
@ -10378,11 +10377,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) {
@ -17809,7 +17805,7 @@ namespace ts {
return getContextualTypeForArgument(<CallExpression | NewExpression>parent, node);
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.AsExpression:
return getTypeFromTypeNode((<AssertionExpression>parent).type);
return isConstTypeReference((<AssertionExpression>parent).type) ? undefined : getTypeFromTypeNode((<AssertionExpression>parent).type);
case SyntaxKind.BinaryExpression:
return getContextualTypeForBinaryOperand(node);
case SyntaxKind.PropertyAssignment:
@ -18095,6 +18091,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) {
@ -18137,7 +18134,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) {
@ -18146,14 +18143,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)) {
@ -18171,7 +18168,7 @@ namespace ts {
}
}
}
return createTupleType(elementTypes, minLength, hasRestElement);
return createTupleType(elementTypes, minLength, hasRestElement, readonly);
}
}
@ -18243,15 +18240,15 @@ namespace ts {
return links.resolvedType;
}
function getObjectLiteralIndexInfo(propertyNodes: NodeArray<ObjectLiteralElementLike>, 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 {
@ -18279,6 +18276,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;
@ -18313,8 +18312,8 @@ namespace ts {
typeFlags |= type.flags;
const nameType = computedNameType && isTypeUsableAsPropertyName(computedNameType) ? computedNameType : undefined;
const prop = nameType ?
createSymbol(SymbolFlags.Property | member.flags, getPropertyNameFromType(nameType), CheckFlags.Late) :
createSymbol(SymbolFlags.Property | member.flags, member.escapedName);
createSymbol(SymbolFlags.Property | member.flags, getPropertyNameFromType(nameType), checkFlags | CheckFlags.Late) :
createSymbol(SymbolFlags.Property | member.flags, member.escapedName, checkFlags);
if (nameType) {
prop.nameType = nameType;
}
@ -18358,7 +18357,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;
@ -18370,7 +18369,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;
}
@ -18420,7 +18419,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;
}
@ -18428,8 +18427,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;
@ -18559,7 +18558,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);
@ -18567,7 +18566,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;
@ -18577,7 +18576,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);
}
}
@ -18609,7 +18608,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);
}
}
@ -21281,7 +21280,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;
@ -21333,12 +21332,39 @@ 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((<ParenthesizedExpression>node).expression);
case SyntaxKind.PrefixUnaryExpression:
const op = (<PrefixUnaryExpression>node).operator;
const arg = (<PrefixUnaryExpression>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) {
const exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(checkExpression(expression, 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);
exprType = getRegularTypeOfObjectLiteral(getBaseTypeOfLiteralType(exprType));
const targetType = getTypeFromTypeNode(type);
if (produceDiagnostics && targetType !== errorType) {
const widenedType = getWidenedType(exprType);
if (!isTypeComparableTo(targetType, widenedType)) {
@ -23058,12 +23084,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);
}
@ -23127,7 +23161,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((<TypeAssertion>expr).type);
}
// Otherwise simply call checkExpression. Ideally, the entire family of checkXXX functions

View file

@ -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",

View file

@ -5607,6 +5607,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;
}

View file

@ -3360,6 +3360,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;

View file

@ -3360,6 +3360,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;

View file

@ -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 = <const> 10;
let q2 = <const> 'abc';
let q3 = <const> true;
let q4 = <const> [1, 2, 3];
let q5 = <const> { x: 10, y: 20 };
declare function id<T>(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.

View file

@ -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 = <const> 10;
let q2 = <const> 'abc';
let q3 = <const> true;
let q4 = <const> [1, 2, 3];
let q5 = <const> { x: 10, y: 20 };
declare function id<T>(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<T>(x: T): T;
declare let e1: "abc";
declare let e2: 0 | 1;
declare let e3: 1;

View file

@ -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 = <const> 10;
>q1 : Symbol(q1, Decl(constAssertions.ts, 52, 3))
let q2 = <const> 'abc';
>q2 : Symbol(q2, Decl(constAssertions.ts, 53, 3))
let q3 = <const> true;
>q3 : Symbol(q3, Decl(constAssertions.ts, 54, 3))
let q4 = <const> [1, 2, 3];
>q4 : Symbol(q4, Decl(constAssertions.ts, 55, 3))
let q5 = <const> { 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<T>(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))

View file

@ -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 = <const> 10;
>q1 : 10
><const> 10 : 10
>10 : 10
let q2 = <const> 'abc';
>q2 : "abc"
><const> 'abc' : "abc"
>'abc' : "abc"
let q3 = <const> true;
>q3 : true
><const> true : true
>true : true
let q4 = <const> [1, 2, 3];
>q4 : readonly [1, 2, 3]
><const> [1, 2, 3] : readonly [1, 2, 3]
>[1, 2, 3] : readonly [1, 2, 3]
>1 : 1
>2 : 2
>3 : 3
let q5 = <const> { x: 10, y: 20 };
>q5 : { readonly x: 10; readonly y: 20; }
><const> { 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<T>(x: T): T;
>id : <T>(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 : <T>(x: T) => T
>1 : 1

View file

@ -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 = <const> 10;
let q2 = <const> 'abc';
let q3 = <const> true;
let q4 = <const> [1, 2, 3];
let q5 = <const> { x: 10, y: 20 };
declare function id<T>(x: T): T;
let e1 = v1 as const; // Error
let e2 = (true ? 1 : 0) as const; // Error
let e3 = id(1) as const; // Error