Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions internal/checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -4549,9 +4549,9 @@ func (c *Checker) checkIndexConstraints(t *Type, symbol *ast.Symbol, isStaticInd
typeDeclaration := symbol.ValueDeclaration
if typeDeclaration != nil && ast.IsClassLike(typeDeclaration) {
for _, member := range typeDeclaration.Members() {
// Only process instance properties with computed names here. Static properties cannot be in conflict with indexers,
// and properties with literal names were already checked.
if !ast.IsStatic(member) && !c.hasBindableName(member) {
// Only process instance properties against instance index signatures and static properties against static index signatures
if ((!isStaticIndex && !ast.IsStatic(member)) ||
(isStaticIndex && ast.IsStatic(member))) && !c.hasBindableName(member) {
symbol := c.getSymbolOfDeclaration(member)
c.checkIndexConstraintForProperty(t, symbol, c.getTypeOfExpression(member.Name().Expression()), c.getNonMissingTypeOfSymbol(symbol))
}
Expand Down
52 changes: 50 additions & 2 deletions internal/checker/nodebuilderimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -1951,6 +1951,48 @@ func (b *nodeBuilderImpl) serializeReturnTypeForSignature(signature *Signature)
return returnTypeNode
}

func (b *nodeBuilderImpl) indexInfoToObjectComputedNamesOrSignatureDeclaration(indexInfo *IndexInfo, typeNode *ast.TypeNode) []*ast.TypeElement {
if len(indexInfo.components) != 0 {
// Index info is derived from object or class computed property names (plus explicit named members) - we can clone those instead of writing out the result computed index signature
allComponentComputedNamesSerializable := b.ctx.enclosingDeclaration != nil && core.Every(indexInfo.components, func(c *ast.Node) bool {
return c.Name() != nil &&
ast.IsComputedPropertyName(c.Name()) &&
ast.IsEntityNameExpression(c.Name().AsComputedPropertyName().Expression) &&
b.ch.GetEmitResolver().isEntityNameVisible(c.Name().AsComputedPropertyName().Expression, b.ctx.enclosingDeclaration, false).Accessibility == printer.SymbolAccessibilityAccessible
})
if allComponentComputedNamesSerializable {
// Only use computed name serialization form if all components are visible and take the `a.b.c` form
var newComponents []*ast.Node
for _, c := range indexInfo.components {
// skip late bound props that contribute to the index signature - they'll be created by property creation anyway
if !b.ch.hasLateBindableName(c) {
newComponents = append(newComponents, c)
}
}
result := make([]*ast.TypeElement, 0, len(newComponents))
for _, c := range newComponents {
// Still need to track visibility even if we've already checked it to paint references as used
b.trackComputedName(c.Name().AsComputedPropertyName().Expression, b.ctx.enclosingDeclaration)
var modifiers *ast.ModifierList
if indexInfo.isReadonly {
modifiers = b.f.NewModifierList([]*ast.Node{b.f.NewModifier(ast.KindReadonlyKeyword)})
}
var questionToken *ast.Node
if c.QuestionToken() != nil {
questionToken = b.f.NewToken(ast.KindQuestionToken)
}
if typeNode == nil {
typeNode = b.typeToTypeNode(b.ch.getTypeOfSymbol(c.Symbol()))
}
propertySignature := b.f.NewPropertySignatureDeclaration(modifiers, c.Name(), questionToken, typeNode, nil)
result = append(result, propertySignature)
}
return result
}
}
return []*ast.TypeElement{b.indexInfoToIndexSignatureDeclarationHelper(indexInfo, typeNode)}
}

func (b *nodeBuilderImpl) indexInfoToIndexSignatureDeclarationHelper(indexInfo *IndexInfo, typeNode *ast.TypeNode) *ast.Node {
name := getNameFromIndexInfo(indexInfo)
indexerTypeNode := b.typeToTypeNode(indexInfo.keyType)
Expand Down Expand Up @@ -2083,9 +2125,15 @@ func (b *nodeBuilderImpl) shouldUsePlaceholderForProperty(propertySymbol *ast.Sy
func (b *nodeBuilderImpl) trackComputedName(accessExpression *ast.Node, enclosingDeclaration *ast.Node) {
// get symbol of the first identifier of the entityName
firstIdentifier := ast.GetFirstIdentifier(accessExpression)
name := b.ch.resolveName(firstIdentifier, firstIdentifier.Text(), ast.SymbolFlagsValue|ast.SymbolFlagsExportValue, nil /*nameNotFoundMessage*/, true /*isUse*/, false)
name := b.ch.resolveName(enclosingDeclaration, firstIdentifier.Text(), ast.SymbolFlagsValue|ast.SymbolFlagsExportValue, nil /*nameNotFoundMessage*/, true /*isUse*/, false)
if name != nil {
b.ctx.tracker.TrackSymbol(name, enclosingDeclaration, ast.SymbolFlagsValue)
} else {
// Name does not resolve at target location, track symbol at dest location (should be inaccessible)
fallback := b.ch.resolveName(firstIdentifier, firstIdentifier.Text(), ast.SymbolFlagsValue|ast.SymbolFlagsExportValue, nil /*nameNotFoundMessage*/, true /*isUse*/, false)
if fallback != nil {
b.ctx.tracker.TrackSymbol(fallback, enclosingDeclaration, ast.SymbolFlagsValue)
}
}
}

Expand Down Expand Up @@ -2331,7 +2379,7 @@ func (b *nodeBuilderImpl) createTypeNodesFromResolvedType(resolvedType *Structur
typeElements = append(typeElements, b.signatureToSignatureDeclarationHelper(signature, ast.KindConstructSignature, nil))
}
for _, info := range resolvedType.indexInfos {
typeElements = append(typeElements, b.indexInfoToIndexSignatureDeclarationHelper(info, core.IfElse(resolvedType.objectFlags&ObjectFlagsReverseMapped != 0, b.createElidedInformationPlaceholder(), nil)))
typeElements = append(typeElements, b.indexInfoToObjectComputedNamesOrSignatureDeclaration(info, core.IfElse(resolvedType.objectFlags&ObjectFlagsReverseMapped != 0, b.createElidedInformationPlaceholder(), nil))...)
}

properties := resolvedType.properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ function foo8(y = (async () => z)(), z = 1) {

// error - used as computed name of method
function foo9(y = {[z]() { return z; }}, z = 1) {
>foo9 : (y?: { [x: number]: () => number; }, z?: number) => void
>y : { [x: number]: () => number; }
>{[z]() { return z; }} : { [x: number]: () => number; }
>foo9 : (y?: { [z]: () => number; }, z?: number) => void
>y : { [z]: () => number; }
>{[z]() { return z; }} : { [z]: () => number; }
>[z] : () => number
>z : number
>z : number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,4 @@
+>{ x: <typeof z>a } : { x: number; }
>x : number
><typeof z>a : number
>z : number
@@= skipped -74, +74 lines =@@

// error - used as computed name of method
function foo9(y = {[z]() { return z; }}, z = 1) {
->foo9 : (y?: { [z]: () => number; }, z?: number) => void
->y : { [z]: () => number; }
->{[z]() { return z; }} : { [z]: () => number; }
+>foo9 : (y?: { [x: number]: () => number; }, z?: number) => void
+>y : { [x: number]: () => number; }
+>{[z]() { return z; }} : { [x: number]: () => number; }
>[z] : () => number
>z : number
>z : number
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ let s = `${n}`;
>n : number

const numericIndex = { [n]: 1 };
>numericIndex : { [x: number]: number; }
>{ [n]: 1 } : { [x: number]: number; }
>numericIndex : { [n]: number; }
>{ [n]: 1 } : { [n]: number; }
>[n] : number
>n : number
>1 : 1
Expand All @@ -26,13 +26,13 @@ numericIndex[n].toFixed();
>numericIndex[n].toFixed() : string
>numericIndex[n].toFixed : (fractionDigits?: number) => string
>numericIndex[n] : number
>numericIndex : { [x: number]: number; }
>numericIndex : { [n]: number; }
>n : number
>toFixed : (fractionDigits?: number) => string

const stringIndex = { [s]: 1 };
>stringIndex : { [x: string]: number; }
>{ [s]: 1 } : { [x: string]: number; }
>stringIndex : { [s]: number; }
>{ [s]: 1 } : { [s]: number; }
>[s] : number
>s : string
>1 : 1
Expand All @@ -41,7 +41,7 @@ stringIndex[s].toFixed();
>stringIndex[s].toFixed() : string
>stringIndex[s].toFixed : (fractionDigits?: number) => string
>stringIndex[s] : number
>stringIndex : { [x: string]: number; }
>stringIndex : { [s]: number; }
>s : string
>toFixed : (fractionDigits?: number) => string

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export declare class A {
}
export declare const Mixer: {
new (): {
[x: symbol]: () => number;
[a]: () => number;
};
} & (new (...args: any[]) => {
mixed: true;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ function f (m: string) {
>m : string

[1, 2, 3].map(i => {
>[1, 2, 3].map(i => { return true? { [m]: i } : { [m]: i + 1 } }) : { [x: string]: number; }[]
>[1, 2, 3].map(i => { return true? { [m]: i } : { [m]: i + 1 } }) : { [m]: number; }[]
>[1, 2, 3].map : <U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[]
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 3
>map : <U>(callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[]
>i => { return true? { [m]: i } : { [m]: i + 1 } } : (i: number) => { [x: string]: number; }
>i => { return true? { [m]: i } : { [m]: i + 1 } } : (i: number) => { [m]: number; }
>i : number

return true? { [m]: i } : { [m]: i + 1 }
>true? { [m]: i } : { [m]: i + 1 } : { [x: string]: number; }
>true? { [m]: i } : { [m]: i + 1 } : { [m]: number; }
>true : true
>{ [m]: i } : { [x: string]: number; }
>{ [m]: i } : { [m]: number; }
>[m] : number
>m : string
>i : number
>{ [m]: i + 1 } : { [x: string]: number; }
>{ [m]: i + 1 } : { [m]: number; }
>[m] : number
>m : string
>i + 1 : number
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}];
({[foo]: bar} = {bar: "bar"});
>({[foo]: bar} = {bar: "bar"}) : { bar: string; }
>{[foo]: bar} = {bar: "bar"} : { bar: string; }
>{[foo]: bar} : { [x: string]: any; }
>{[foo]: bar} : { [foo]: any; }
>[foo] : any
>foo : string
>bar : any
Expand Down Expand Up @@ -140,8 +140,8 @@ let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}];

[{[foo]: bar4}] = [{bar: "bar"}];
>[{[foo]: bar4}] = [{bar: "bar"}] : [{ bar: string; }]
>[{[foo]: bar4}] : [{ [x: string]: any; }]
>{[foo]: bar4} : { [x: string]: any; }
>[{[foo]: bar4}] : [{ [foo]: any; }]
>{[foo]: bar4} : { [foo]: any; }
>[foo] : any
>foo : string
>bar4 : any
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}];
({[foo]: bar} = {bar: "bar"});
>({[foo]: bar} = {bar: "bar"}) : { bar: string; }
>{[foo]: bar} = {bar: "bar"} : { bar: string; }
>{[foo]: bar} : { [x: string]: any; }
>{[foo]: bar} : { [foo]: any; }
>[foo] : any
>foo : string
>bar : any
Expand Down Expand Up @@ -147,8 +147,8 @@ let [{[foo.toExponential()]: bar7}] = [{bar: "bar"}];

[{[foo]: bar4}] = [{bar: "bar"}];
>[{[foo]: bar4}] = [{bar: "bar"}] : [{ bar: string; }]
>[{[foo]: bar4}] : [{ [x: string]: any; }]
>{[foo]: bar4} : { [x: string]: any; }
>[{[foo]: bar4}] : [{ [foo]: any; }]
>{[foo]: bar4} : { [foo]: any; }
>[foo] : any
>foo : string
>bar4 : any
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,9 @@ export declare let o31: {
export declare let o32: {
[x: number]: number;
};
declare let u: symbol;
export declare let o4: {
[x: symbol]: number;
[u]: number;
};
export declare let o5: {
[x: symbol]: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@
+export declare let o32: {
+ [x: number]: number;
+};
+declare let u: symbol;
+export declare let o4: {
+ [x: symbol]: number;
+ [u]: number;
+};
+export declare let o5: {
+ [x: symbol]: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ let u = Symbol();
>Symbol : SymbolConstructor

export let o4 = {
>o4 : { [x: symbol]: number; }
>{ [u]: 1 // Should error, nut a unique symbol} : { [x: symbol]: number; }
>o4 : { [u]: number; }
>{ [u]: 1 // Should error, nut a unique symbol} : { [u]: number; }

[u]: 1 // Should error, nut a unique symbol
>[u] : number
Expand Down

This file was deleted.

Loading