Skip to content
12 changes: 12 additions & 0 deletions tsc/internal/checker/exports.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package checker

import (
"maps"
"slices"

"github.com/microsoft/TypeScript/tsc/internal/ast"
"github.com/microsoft/TypeScript/tsc/internal/diagnostics"
)
Expand Down Expand Up @@ -359,6 +362,15 @@ func (c *Checker) GetIndexInfosOfType(t *Type) []*IndexInfo {
return c.getIndexInfosOfType(t)
}

func (c *Checker) GetIndexInfosOfIndexSymbol(symbol *ast.Symbol) []*IndexInfo {
var siblingSymbols []*ast.Symbol
if symbol.Parent() != nil {
siblingSymbols = slices.Collect(maps.Values(c.getMembersOfSymbol(symbol.Parent())))
c.sortSymbols(siblingSymbols)
}
return c.getIndexInfosOfIndexSymbol(symbol, siblingSymbols)
}

func (c *Checker) IsContextSensitive(node *ast.Node) bool {
return c.isContextSensitive(node)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

func TestJsDocPropertyDescription1(t *testing.T) {
t.Skip("Known failing fourslash test")
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `interface StringExample {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

func TestJsDocPropertyDescription4(t *testing.T) {
t.Skip("Known failing fourslash test")
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `interface MultipleExample {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

func TestJsDocPropertyDescription7(t *testing.T) {
t.Skip("Known failing fourslash test")
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `class StringClass {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package fourslash_test

import (
"testing"

"github.com/microsoft/TypeScript/tsc/internal/fourslash"
"github.com/microsoft/TypeScript/tsc/internal/testutil"
)

func TestQuickInfoIndexSignatureOwnerAlias(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
namespace Outer {
export namespace Inner {
export interface Dictionary { [k: string]: number; }
}
}
import Alias = Outer.Inner;
declare const dictionary: Alias.Dictionary;
dictionary./*alias*/aliasKey;
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyQuickInfoAt(t, "alias", "(index) Dictionary[string]: number", "")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package fourslash_test

import (
"testing"

"github.com/microsoft/TypeScript/tsc/internal/fourslash"
"github.com/microsoft/TypeScript/tsc/internal/testutil"
)

func TestQuickInfoIndexSignatureOwnerNamespace(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
namespace Outer {
export namespace Inner {
export interface Dictionary { [k: string]: number; }
declare const inside: Dictionary;
inside./*inside*/insideKey;
}
}
namespace Other {
export interface Dictionary { [k: string]: number; }
}
declare const outside: Outer.Inner.Dictionary;
outside./*outside*/outsideKey;
declare const other: Other.Dictionary;
other./*other*/otherKey;
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyQuickInfoAt(t, "inside", "(index) Dictionary[string]: number", "")
f.VerifyQuickInfoAt(t, "outside", "(index) Dictionary[string]: number", "")
f.VerifyQuickInfoAt(t, "other", "(index) Dictionary[string]: number", "")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package fourslash_test

import (
"testing"

"github.com/microsoft/TypeScript/tsc/internal/fourslash"
"github.com/microsoft/TypeScript/tsc/internal/testutil"
)

func TestQuickInfoIndexSignaturePropertyUnchecked(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `
// @strict: true
// @noUncheckedIndexedAccess: true
interface Dictionary {
/** The stored value. */
[k: string]: number;
}
declare const dictionary: Dictionary;
dictionary./*read*/a;
dictionary./*write*/a = 1;
if (dictionary.a !== undefined) {
dictionary./*narrowed*/a;
}
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyQuickInfoAt(t, "read", "(index) Dictionary[string]: number | undefined", "The stored value.")
f.VerifyQuickInfoAt(t, "write", "(index) Dictionary[string]: number", "The stored value.")
f.VerifyQuickInfoAt(t, "narrowed", "(index) Dictionary[string]: number", "The stored value.")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fourslash_test

import (
"testing"

"github.com/microsoft/TypeScript/tsc/internal/fourslash"
"github.com/microsoft/TypeScript/tsc/internal/testutil"
)

func TestQuickInfoIndexSignatureProperty(t *testing.T) {
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
// Regression test for https://github.com/microsoft/TypeScript/issues/64582.
const content = `
// @strict: true
declare const x: { [k: string]: number };
x./*anonymous*/a;
interface Dictionary<T> {
[k: string]: T;
}

declare const dictionary: Dictionary<number>;
dictionary./*generic*/a;
interface Multiple {
[k: string | symbol]: number;
}
declare const multiple: Multiple;
multiple./*multiple*/a;
interface Pattern {
[k: ` + "`data_${string}`" + `]: number;
}
declare const pattern: Pattern;
pattern./*pattern*/data_example;
`
f, done := fourslash.NewFourslash(t, nil /*capabilities*/, content)
defer done()
f.VerifyQuickInfoAt(t, "anonymous", "(index) x[string]: number", "")
f.VerifyQuickInfoAt(t, "generic", "(index) Dictionary[string]: number", "")
f.VerifyQuickInfoAt(t, "multiple", "(index) Multiple[string | symbol]: number", "")
f.VerifyQuickInfoAt(t, "pattern", "(index) Pattern[`data_${string}`]: number", "")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
)

func TestQuickInfoOnPropDeclaredUsingIndexSignatureOnInterfaceWithBase(t *testing.T) {
t.Skip("Known failing fourslash test")
t.Parallel()
defer testutil.RecoverAndFail(t, "Panic on fourslash test")
const content = `interface P {}
Expand Down
17 changes: 16 additions & 1 deletion tsc/internal/ls/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,22 @@ func getQuickInfoAndDeclarationAtLocation(c *checker.Checker, symbol *ast.Symbol
}
if flags&(ast.SymbolFlagsVariable|ast.SymbolFlagsProperty|ast.SymbolFlagsAccessor) != 0 {
writeNewLine()
if symbol.CheckFlags()&ast.CheckFlagsIndexSymbol == 0 {
if symbol.CheckFlags()&ast.CheckFlagsIndexSymbol != 0 {
dpw.WritePunctuation("(")
dpw.Write("index")
dpw.WritePunctuation(") ")
if symbol.Parent() != nil {
writeSymbolClassified(symbol.Parent(), nil, ast.SymbolFlagsNone, symbolFormatFlags)
}
dpw.WritePunctuation("[")
for i, info := range c.GetIndexInfosOfIndexSymbol(symbol) {
if i != 0 {
dpw.WritePunctuation(" | ")
}
writeTypeClassified(info.KeyType(), container, typeFormatFlags)
}
dpw.WritePunctuation("]: ")
} else {
switch {
case flags&ast.SymbolFlagsProperty != 0:
dpw.WritePunctuation("(")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// ^^^
// | ----------------------------------------------------------------------
// | ```typescript
// | any
// | (index) IntrinsicElements[string]: any
// | ```
// |
// | ----------------------------------------------------------------------
Expand All @@ -25,7 +25,7 @@
"item": {
"contents": {
"kind": "markdown",
"value": "```typescript\nany\n```\n"
"value": "```typescript\n(index) IntrinsicElements[string]: any\n```\n"
},
"range": {
"start": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@
// ^^^^^^
// | ----------------------------------------------------------------------
// | ```typescript
// | any
// | (index) IntrinsicElements[`foo${string}`]: any
// | ```
// |
// | ----------------------------------------------------------------------
// <foobarbaz />;
// ^^^^^^^^^
// | ----------------------------------------------------------------------
// | ```typescript
// | any
// | (index) IntrinsicElements[`foo${string}` | `foobar${string}`]: any
// | ```
// |
// | ----------------------------------------------------------------------
Expand All @@ -36,7 +36,7 @@
"item": {
"contents": {
"kind": "markdown",
"value": "```typescript\nany\n```\n"
"value": "```typescript\n(index) IntrinsicElements[`foo${string}`]: any\n```\n"
},
"range": {
"start": {
Expand All @@ -63,7 +63,7 @@
"item": {
"contents": {
"kind": "markdown",
"value": "```typescript\nany\n```\n"
"value": "```typescript\n(index) IntrinsicElements[`foo${string}` | `foobar${string}`]: any\n```\n"
},
"range": {
"start": {
Expand Down
Loading