@@ -425,7 +425,6 @@ namespace ts {
425
425
const resolvingSignaturesArray = [resolvingSignature];
426
426
427
427
const enumNumberIndexInfo = createIndexInfo(stringType, /*isReadonly*/ true);
428
- const jsObjectLiteralIndexInfo = createIndexInfo(anyType, /*isReadonly*/ false);
429
428
430
429
const globals = createSymbolTable();
431
430
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 {
4809
4808
members.set(name, s);
4810
4809
}
4811
4810
});
4812
- return createAnonymousType(
4811
+ const result = createAnonymousType(
4813
4812
exportedType.symbol,
4814
4813
members,
4815
4814
exportedType.callSignatures,
4816
4815
exportedType.constructSignatures,
4817
4816
exportedType.stringIndexInfo,
4818
4817
exportedType.numberIndexInfo);
4818
+ result.objectFlags |= (getObjectFlags(type) & ObjectFlags.JSLiteral); // Propagate JSLiteral flag
4819
+ return result;
4819
4820
}
4820
4821
if (isEmptyArrayLiteralType(type)) {
4821
4822
if (noImplicitAny) {
@@ -5123,7 +5124,9 @@ namespace ts {
5123
5124
if (s && hasEntries(s.exports)) {
5124
5125
mergeSymbolTable(exports, s.exports);
5125
5126
}
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;
5127
5130
}
5128
5131
}
5129
5132
@@ -9074,6 +9077,34 @@ namespace ts {
9074
9077
return type;
9075
9078
}
9076
9079
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
+
9077
9108
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode | undefined, cacheSymbol: boolean) {
9078
9109
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
9079
9110
const propName = isTypeUsableAsLateBoundName(indexType) ? getLateBoundNameFromType(indexType) :
@@ -9122,6 +9153,9 @@ namespace ts {
9122
9153
if (indexType.flags & TypeFlags.Never) {
9123
9154
return neverType;
9124
9155
}
9156
+ if (isJSLiteralType(objectType)) {
9157
+ return anyType;
9158
+ }
9125
9159
if (accessExpression && !isConstEnumObjectType(objectType)) {
9126
9160
if (noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) {
9127
9161
if (getIndexTypeOfType(objectType, IndexKind.Number)) {
@@ -9142,6 +9176,9 @@ namespace ts {
9142
9176
return anyType;
9143
9177
}
9144
9178
}
9179
+ if (isJSLiteralType(objectType)) {
9180
+ return anyType;
9181
+ }
9145
9182
if (accessNode) {
9146
9183
const indexNode = accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode.argumentExpression : accessNode.indexType;
9147
9184
if (indexType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral)) {
@@ -11217,6 +11254,9 @@ namespace ts {
11217
11254
}
11218
11255
11219
11256
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
+ }
11220
11260
if (maybeTypeOfKind(target, TypeFlags.Object) && !(getObjectFlags(target) & ObjectFlags.ObjectLiteralPatternWithComputedProperties)) {
11221
11261
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
11222
11262
if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
@@ -12705,7 +12745,7 @@ namespace ts {
12705
12745
resolved.stringIndexInfo,
12706
12746
resolved.numberIndexInfo);
12707
12747
regularNew.flags = resolved.flags & ~TypeFlags.FreshLiteral;
12708
- regularNew.objectFlags |= ObjectFlags.ObjectLiteral;
12748
+ regularNew.objectFlags |= ObjectFlags.ObjectLiteral | (getObjectFlags(resolved) & ObjectFlags.JSLiteral) ;
12709
12749
(<FreshObjectLiteralType>type).regularType = regularNew;
12710
12750
return regularNew;
12711
12751
}
@@ -12784,9 +12824,11 @@ namespace ts {
12784
12824
}
12785
12825
const stringIndexInfo = getIndexInfoOfType(type, IndexKind.String);
12786
12826
const numberIndexInfo = getIndexInfoOfType(type, IndexKind.Number);
12787
- return createAnonymousType(type.symbol, members, emptyArray, emptyArray,
12827
+ const result = createAnonymousType(type.symbol, members, emptyArray, emptyArray,
12788
12828
stringIndexInfo && createIndexInfo(getWidenedType(stringIndexInfo.type), stringIndexInfo.isReadonly),
12789
12829
numberIndexInfo && createIndexInfo(getWidenedType(numberIndexInfo.type), numberIndexInfo.isReadonly));
12830
+ result.objectFlags |= (getObjectFlags(type) & ObjectFlags.JSLiteral); // Retain js literal flag through widening
12831
+ return result;
12790
12832
}
12791
12833
12792
12834
function getWidenedType(type: Type) {
@@ -16791,12 +16833,15 @@ namespace ts {
16791
16833
return createObjectLiteralType();
16792
16834
16793
16835
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;
16795
16837
const numberIndexInfo = hasComputedNumberProperty && !isJSObjectLiteral ? getObjectLiteralIndexInfo(node.properties, offset, propertiesArray, IndexKind.Number) : undefined;
16796
16838
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
16797
16839
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshLiteral;
16798
16840
result.flags |= TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags);
16799
16841
result.objectFlags |= ObjectFlags.ObjectLiteral;
16842
+ if (isJSObjectLiteral) {
16843
+ result.objectFlags |= ObjectFlags.JSLiteral;
16844
+ }
16800
16845
if (patternWithComputedProperties) {
16801
16846
result.objectFlags |= ObjectFlags.ObjectLiteralPatternWithComputedProperties;
16802
16847
}
@@ -17872,6 +17917,9 @@ namespace ts {
17872
17917
if (!prop) {
17873
17918
const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String);
17874
17919
if (!(indexInfo && indexInfo.type)) {
17920
+ if (isJSLiteralType(leftType)) {
17921
+ return anyType;
17922
+ }
17875
17923
if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) {
17876
17924
reportNonexistentProperty(right, leftType.flags & TypeFlags.TypeParameter && (leftType as TypeParameter).isThisType ? apparentType : leftType);
17877
17925
}
@@ -20009,7 +20057,8 @@ namespace ts {
20009
20057
if (decl) {
20010
20058
const jsSymbol = getSymbolOfNode(decl);
20011
20059
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;
20013
20062
}
20014
20063
}
20015
20064
}
0 commit comments