@@ -425,7 +425,6 @@ namespace ts {
425425 const resolvingSignaturesArray = [resolvingSignature];
426426
427427 const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
428- const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
429428
430429 const globals = createSymbolTable();
431430 let amalgamatedDuplicates: Map<{ firstFile: SourceFile, secondFile: SourceFile, firstFileInstances: Map<{ instances: Node[], blockScoped: boolean }>, secondFileInstances: Map<{ instances: Node[], blockScoped: boolean }> }> | undefined;
@@ -4809,13 +4808,15 @@ namespace ts {
48094808 members.set(name, s);
48104809 }
48114810 });
4812- return createAnonymousType(
4811+ const result = createAnonymousType(
48134812 exportedType.symbol,
48144813 members,
48154814 exportedType.callSignatures,
48164815 exportedType.constructSignatures,
48174816 exportedType.stringIndexInfo,
48184817 exportedType.numberIndexInfo);
4818+ result.objectFlags |= (getObjectFlags(type) & ObjectFlags.JSLiteral); // Propagate JSLiteral flag
4819+ return result;
48194820 }
48204821 if (isEmptyArrayLiteralType(type)) {
48214822 if (noImplicitAny) {
@@ -5123,7 +5124,9 @@ namespace ts {
51235124 if (s && hasEntries(s.exports)) {
51245125 mergeSymbolTable(exports, s.exports);
51255126 }
5126- return createAnonymousType(symbol, exports, emptyArray, emptyArray, jsObjectLiteralIndexInfo, undefined);
5127+ const type = createAnonymousType(symbol, exports, emptyArray, emptyArray, undefined, undefined);
5128+ type.objectFlags |= ObjectFlags.JSLiteral;
5129+ return type;
51275130 }
51285131 }
51295132
@@ -9074,6 +9077,34 @@ namespace ts {
90749077 return type;
90759078 }
90769079
9080+ /**
9081+ * Returns if a type is or consists of a JSLiteral object type
9082+ * In addition to objects which are directly literals,
9083+ * * unions where every element is a jsliteral
9084+ * * intersections where at least one element is a jsliteral
9085+ * * and instantiable types constrained to a jsliteral
9086+ * Should all count as literals and not print errors on access or assignment of possibly existing properties.
9087+ * This mirrors the behavior of the index signature propagation, to which this behaves similarly (but doesn't affect assignability or inference).
9088+ */
9089+ function isJSLiteralType(type: Type): boolean {
9090+ if (noImplicitAny) {
9091+ return false; // Flag is meaningless under `noImplicitAny` mode
9092+ }
9093+ if (getObjectFlags(type) & ObjectFlags.JSLiteral) {
9094+ return true;
9095+ }
9096+ if (type.flags & TypeFlags.Union) {
9097+ return every((type as UnionType).types, isJSLiteralType);
9098+ }
9099+ if (type.flags & TypeFlags.Intersection) {
9100+ return some((type as IntersectionType).types, isJSLiteralType);
9101+ }
9102+ if (type.flags & TypeFlags.Instantiable) {
9103+ return isJSLiteralType(getResolvedBaseConstraint(type));
9104+ }
9105+ return false;
9106+ }
9107+
90779108 function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean) {
90789109 const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
90799110 const propName = isTypeUsableAsLateBoundName(indexType) ? getLateBoundNameFromType(indexType) :
@@ -9122,6 +9153,9 @@ namespace ts {
91229153 if (indexType.flags & TypeFlags.Never) {
91239154 return neverType;
91249155 }
9156+ if (isJSLiteralType(objectType)) {
9157+ return anyType;
9158+ }
91259159 if (accessExpression && !isConstEnumObjectType(objectType)) {
91269160 if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) {
91279161 if (getIndexTypeOfType(objectType, IndexKind.Number)) {
@@ -9142,6 +9176,9 @@ namespace ts {
91429176 return anyType;
91439177 }
91449178 }
9179+ if (isJSLiteralType(objectType)) {
9180+ return anyType;
9181+ }
91459182 if (accessNode) {
91469183 const indexNode = accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression : accessNode.indexType;
91479184 if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
@@ -11217,6 +11254,9 @@ namespace ts {
1121711254 }
1121811255
1121911256 function hasExcessProperties(source: FreshObjectLiteralType, target: Type, discriminant: Type | undefined, reportErrors: boolean): boolean {
11257+ if (!noImplicitAny && getObjectFlags(target) & ObjectFlags.JSLiteral) {
11258+ return false; // Disable excess property checks on JS literals to simulate having an implicit "index signature" - but only outside of noImplicitAny
11259+ }
1122011260 if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
1122111261 const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
1122211262 if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
@@ -12705,7 +12745,7 @@ namespace ts {
1270512745 resolved.stringIndexInfo,
1270612746 resolved.numberIndexInfo);
1270712747 regularNew.flags = resolved.flags & ~TypeFlags.FreshLiteral;
12708- regularNew.objectFlags |= ObjectFlags.ObjectLiteral;
12748+ regularNew.objectFlags |= ObjectFlags.ObjectLiteral | (getObjectFlags(resolved) & ObjectFlags.JSLiteral) ;
1270912749 (<FreshObjectLiteralType>type).regularType = regularNew;
1271012750 return regularNew;
1271112751 }
@@ -12784,9 +12824,11 @@ namespace ts {
1278412824 }
1278512825 const stringIndexInfo = getIndexInfoOfType(type, IndexKind.String);
1278612826 const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number);
12787- return createAnonymousType(type.symbol, members, emptyArray, emptyArray,
12827+ const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray,
1278812828 stringIndexInfo && createIndexInfo(getWidenedType(stringIndexInfo.type), stringIndexInfo.isReadonly),
1278912829 numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly));
12830+ result.objectFlags |= (getObjectFlags(type) & ObjectFlags.JSLiteral); // Retain js literal flag through widening
12831+ return result;
1279012832 }
1279112833
1279212834 function getWidenedType(type: Type) {
@@ -16791,12 +16833,15 @@ namespace ts {
1679116833 return createObjectLiteralType();
1679216834
1679316835 function createObjectLiteralType() {
16794- const stringIndexInfo = isJSObjectLiteral ? jsObjectLiteralIndexInfo : hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
16836+ const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.String) : undefined;
1679516837 const numberIndexInfo = hasComputedNumberProperty && !isJSObjectLiteral ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
1679616838 const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
1679716839 const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
1679816840 result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
1679916841 result.objectFlags |= ObjectFlags.ObjectLiteral;
16842+ if (isJSObjectLiteral) {
16843+ result.objectFlags |= ObjectFlags.JSLiteral;
16844+ }
1680016845 if (patternWithComputedProperties) {
1680116846 result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
1680216847 }
@@ -17872,6 +17917,9 @@ namespace ts {
1787217917 if (!prop) {
1787317918 const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String);
1787417919 if (!(indexInfo && indexInfo.type)) {
17920+ if (isJSLiteralType(leftType)) {
17921+ return anyType;
17922+ }
1787517923 if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) {
1787617924 reportNonexistentProperty(right, leftType.flags & TypeFlags.TypeParameter && (leftType as TypeParameter).isThisType ? apparentType : leftType);
1787717925 }
@@ -20009,7 +20057,8 @@ namespace ts {
2000920057 if (decl) {
2001020058 const jsSymbol = getSymbolOfNode(decl);
2001120059 if (jsSymbol && hasEntries(jsSymbol.exports)) {
20012- jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, jsObjectLiteralIndexInfo, undefined);
20060+ jsAssignmentType = createAnonymousType(jsSymbol, jsSymbol.exports, emptyArray, emptyArray, undefined, undefined);
20061+ (jsAssignmentType as ObjectType).objectFlags |= ObjectFlags.JSLiteral;
2001320062 }
2001420063 }
2001520064 }
0 commit comments