Skip to content

Commit 3c0bea6

Browse files
Fix type lookup for Effect heritage clauses (#706)
1 parent 29b528e commit 3c0bea6

File tree

8 files changed

+58
-0
lines changed

8 files changed

+58
-0
lines changed

.changeset/five-flies-bathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@effect/language-service": patch
3+
---
4+
5+
Fix `getTypeAtLocation` to ignore type-only heritage expressions like `interface X extends Effect.Effect<...>` so the language service no longer triggers bogus TS2689 diagnostics.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
no codefixes
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// no diagnostics
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as Effect from "effect/Effect"
2+
3+
export interface Abc extends Effect.Effect<never, never, never> {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
no codefixes
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// no diagnostics
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as Effect from "effect/Effect"
2+
3+
export interface Abc extends Effect.Effect<never, never, never> {}

packages/language-service/src/core/TypeCheckerUtils.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,11 +490,54 @@ export function makeTypeCheckerUtils(
490490
if (node.parent && ts.isJsxClosingElement(node.parent) && node.parent.tagName === node) return
491491
if (node.parent && ts.isJsxAttribute(node.parent) && node.parent.name === node) return
492492

493+
if (isInsideTypeOnlyHeritageExpression(node)) return
494+
493495
if (ts.isExpression(node) || ts.isTypeNode(node)) {
494496
return typeChecker.getTypeAtLocation(node)
495497
}
496498
}
497499

500+
function isInsideTypeOnlyHeritageExpression(node: ts.Node): boolean {
501+
if (ts.isExpressionWithTypeArguments(node)) {
502+
return isTypeOnlyHeritageClause(node.parent)
503+
}
504+
505+
if (!ts.isIdentifier(node) && !ts.isPropertyAccessExpression(node)) {
506+
return false
507+
}
508+
509+
for (let current = node.parent; current; current = current.parent) {
510+
if (ts.isPropertyAccessExpression(current)) {
511+
continue
512+
}
513+
514+
if (ts.isExpressionWithTypeArguments(current)) {
515+
return isTypeOnlyHeritageClause(current.parent)
516+
}
517+
518+
return false
519+
}
520+
521+
return false
522+
}
523+
524+
function isTypeOnlyHeritageClause(node: ts.Node | undefined): boolean {
525+
if (!node || !ts.isHeritageClause(node)) {
526+
return false
527+
}
528+
529+
const container = node.parent
530+
if (!container) {
531+
return false
532+
}
533+
534+
if (ts.isInterfaceDeclaration(container)) {
535+
return true
536+
}
537+
538+
return ts.isClassLike(container) && node.token === ts.SyntaxKind.ImplementsKeyword
539+
}
540+
498541
function resolveToGlobalSymbol(symbol: ts.Symbol): ts.Symbol {
499542
if (symbol.flags & ts.SymbolFlags.Alias) {
500543
symbol = typeChecker.getAliasedSymbol(symbol)

0 commit comments

Comments
 (0)