Skip to content

Commit cfdf751

Browse files
committed
Make index signatures work on spread types
Previously, they worked when they came from a spread type but not when written in the object literal itself.
1 parent 9a7ebb0 commit cfdf751

File tree

1 file changed

+34
-25
lines changed

1 file changed

+34
-25
lines changed

src/compiler/checker.ts

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2321,6 +2321,9 @@ namespace ts {
23212321
printFollowingPunctuation = true;
23222322
}
23232323
}
2324+
const resolved = resolveStructuredTypeMembers(type);
2325+
writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword);
2326+
writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword);
23242327
writer.decreaseIndent();
23252328
if (printFollowingPunctuation) {
23262329
writeSpace(writer);
@@ -4306,15 +4309,14 @@ namespace ts {
43064309

43074310
function resolveSpreadTypeMembers(type: SpreadType) {
43084311
// The members and properties collections are empty for spread types. To get all properties of an
4309-
// spread type use getPropertiesOfType (only the language service uses this).
4310-
let stringIndexInfo: IndexInfo = undefined;
4311-
let numberIndexInfo: IndexInfo = undefined;
4312+
// spread type use getPropertiesOfType.
4313+
let stringIndexInfo: IndexInfo = getIndexInfoOfSymbol(type.symbol, IndexKind.String);
4314+
let numberIndexInfo: IndexInfo = getIndexInfoOfSymbol(type.symbol, IndexKind.Number);
43124315
for (let i = type.types.length - 1; i > -1; i--) {
43134316
const t = type.types[i];
4314-
stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String));
4315-
numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number));
4316-
if (!t.symbol || !(t.symbol.flags & SymbolFlags.Optional)) {
4317-
break;
4317+
if (!t.isDeclaredProperty) {
4318+
stringIndexInfo = intersectIndexInfos(stringIndexInfo, getIndexInfoOfType(t, IndexKind.String));
4319+
numberIndexInfo = intersectIndexInfos(numberIndexInfo, getIndexInfoOfType(t, IndexKind.Number));
43184320
}
43194321
}
43204322
setObjectTypeMembers(type, emptySymbols, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
@@ -4545,6 +4547,9 @@ namespace ts {
45454547
result.containingType = containingType;
45464548
result.hasCommonType = hasCommonType;
45474549
result.declarations = declarations;
4550+
if (declarations.length) {
4551+
result.valueDeclaration = declarations[0];
4552+
}
45484553
result.isReadonly = isReadonly;
45494554
result.type = containingType.flags & TypeFlags.Intersection ? getIntersectionType(propTypes) : getUnionType(propTypes);
45504555
return result;
@@ -5059,7 +5064,7 @@ namespace ts {
50595064
const declaration = getIndexDeclarationOfSymbol(symbol, kind);
50605065
if (declaration) {
50615066
return createIndexInfo(declaration.type ? getTypeFromTypeNode(declaration.type) : anyType,
5062-
(getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration);
5067+
(getModifierFlags(declaration) & ModifierFlags.Readonly) !== 0, declaration);
50635068
}
50645069
return undefined;
50655070
}
@@ -5683,11 +5688,15 @@ namespace ts {
56835688
}
56845689
spreads.push(getTypeFromTypeNode((member as SpreadTypeElement).type) as SpreadElementType);
56855690
}
5686-
else if (member.kind !== SyntaxKind.CallSignature && member.kind !== SyntaxKind.ConstructSignature) {
5687-
// note that spread types don't include call and construct signatures
5691+
else if (member.kind !== SyntaxKind.CallSignature &&
5692+
member.kind !== SyntaxKind.ConstructSignature &&
5693+
member.kind !== SyntaxKind.IndexSignature) {
5694+
// note that spread types don't include call and construct signatures, and index signatures are resolved later
56885695
const flags = SymbolFlags.Property | SymbolFlags.Transient | (member.questionToken ? SymbolFlags.Optional : 0);
56895696
const text = getTextOfPropertyName(member.name);
56905697
const symbol = <TransientSymbol>createSymbol(flags, text);
5698+
symbol.declarations = [member];
5699+
symbol.valueDeclaration = member;
56915700
symbol.type = getTypeFromTypeNodeNoAlias((member as IndexSignatureDeclaration | PropertySignature | MethodSignature).type);
56925701
if (!members) {
56935702
members = createMap<Symbol>();
@@ -10458,7 +10467,7 @@ namespace ts {
1045810467
}
1045910468
else if (memberDecl.kind === SyntaxKind.SpreadElementExpression) {
1046010469
if (propertiesArray.length > 0) {
10461-
const t = createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern) as SpreadElementType;
10470+
const t = createObjectLiteralType() as SpreadElementType;
1046210471
t.isDeclaredProperty = true;
1046310472
spreads.push(t);
1046410473
propertiesArray = [];
@@ -10510,7 +10519,7 @@ namespace ts {
1051010519

1051110520
if (spreads.length > 0) {
1051210521
if (propertiesArray.length > 0) {
10513-
const t = createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern) as SpreadElementType;
10522+
const t = createObjectLiteralType() as SpreadElementType;
1051410523
t.isDeclaredProperty = true;
1051510524
spreads.push(t);
1051610525
}
@@ -10520,20 +10529,20 @@ namespace ts {
1052010529
return spread;
1052110530
}
1052210531

10523-
return createObjectLiteralType(node, hasComputedStringProperty, hasComputedNumberProperty, propertiesArray, propertiesTable, typeFlags, patternWithComputedProperties, inDestructuringPattern);
10524-
}
10525-
10526-
function createObjectLiteralType(node: ObjectLiteralExpression, hasComputedStringProperty: boolean, hasComputedNumberProperty: boolean, propertiesArray: Symbol[], propertiesTable: Map<Symbol>, typeFlags: TypeFlags, patternWithComputedProperties: boolean, inDestructuringPattern: boolean) {
10527-
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
10528-
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
10529-
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
10530-
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral;
10531-
result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0);
10532-
if (inDestructuringPattern) {
10533-
result.pattern = node;
10532+
return createObjectLiteralType();
10533+
function createObjectLiteralType() {
10534+
const stringIndexInfo = hasComputedStringProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.String) : undefined;
10535+
const numberIndexInfo = hasComputedNumberProperty ? getObjectLiteralIndexInfo(node, propertiesArray, IndexKind.Number) : undefined;
10536+
const result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
10537+
const freshObjectLiteralFlag = compilerOptions.suppressExcessPropertyErrors ? 0 : TypeFlags.FreshObjectLiteral;
10538+
result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | freshObjectLiteralFlag | (typeFlags & TypeFlags.PropagatingFlags) | (patternWithComputedProperties ? TypeFlags.ObjectLiteralPatternWithComputedProperties : 0);
10539+
if (inDestructuringPattern) {
10540+
result.pattern = node;
10541+
}
10542+
return result;
1053410543
}
10535-
return result;
10536-
}
10544+
10545+
}
1053710546

1053810547
function checkJsxSelfClosingElement(node: JsxSelfClosingElement) {
1053910548
checkJsxOpeningLikeElement(node);

0 commit comments

Comments
 (0)