microsoft / microsoft/TypeScript

Resolution order dependent circular heritage

Open
#61,711 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Domain: check: Type Circularity Help Wanted Possible Improvement
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

### 🔎 Search Terms

resolution order dependent circular heritage, circular base type, circular mixin

### 🕗 Version & Regression Information

- This changed in #39675

However, it appears this PR was the first time that circular heritage was (consistently) reported. Therefore this issue has essentially always existed.

### ⏯ Playground Link

https://www.typescriptlang.org/play/?#code/PTAEDEEsA8FMBNSQGagJ4HsCuoDGGBbA2AOwBdQyALSAZ1ABtITZRsKMAnUWgd0jK4qlDKAAGAQVxkuABQAqAJQBMsMQDoAUPFi4GAQ06t8JWhWgAuUAElTZfSVyx5aAA6wAPGTewMqKTKcCiqwAHwA3JpRIKAAqrQIIjxUGLyUVPocJAxooPqgOu4kOo65GCTi8mJI9CxOtLSGuchc6caQnLhYBpwCaFoxEvTMADRtoMjM+gygRrQYDABuiYvTWKzwGLC1GBQEmWSwnFre7qAAIrBF8LQA8iQe8qGgALx5JGiR2ro9xgYNoACrQA3ppQKBXJwMK4rJdrncHgFIMsAKLIZC6MgAbQARJDoTiALoRTQAXyiOj0hlYJH0xForn0ThshwIoFB4JiUDgiBQ6GwPH4gmE1DoSQcSHIR2QTNgWnBp1Y1gIrgYsGI5EykHKrxsdgcThc7g85wwXQ1ZAAwv9aJbypMAOa46ysokk8nfKlGPA2lnq9lg0CWC5XUg3e4eJGo9GY3H41xuyIerkwRJ8zA4IwEDDLcZiADKWAARka1KAHaQjpBcBDDHTYIdjpoqQCgUElKoPIWSz5dQ40M9YNBDsV6G32cmwNy06gM7N1TnWNRWAXi6XqhWWL0a4zOPXG1oW-QXergp3u6W+x9B8Ow8fWROosxGzLmabzaQrTa7SRHQHOVOqa8rOApCA4FbiIqfiAtIcgdmWMiQT40Ftmenj9qEYiBm2VhQf4sHtiEXwARAQFICBOBgSQEFiHhfoEGh1SIbRyGoCeDHwR4GFYeC7G4ax9FoUmFI-NSPr6K20jIrAaIYtIoBDiONygNakCfu+WAWgAsjAzAABQAEISbAUYyTG0gAJT-hCUIwqAJCaUWRzCZ6vwTFgjhkNqFSqepZqaZ+OnQMwHiBimPLkfyOAMBgGAJBUy54OUZh7s+bCoGIRkJNaEm0BogZZbAOUAopd72bAaR6eo1WGA6tBWP2WKElZLzPBgRYAFaYiMmihIZxlWIVxW0BZg3GcNXyUm5R6gIVpmyZi1kmClWAEVVNWcHVsKhqOEbseoyqquqn5auUoQWUmQA

### 💻 Code

```ts
// Fixed if you comment this line out or switch to `ActorPTR2e`.
declare const x: InstanceType;

// Used to show that only a dependency on `T` is necessary for the circularity.
// As in, the final resolved value does not matter.
type DependsOn = any;

declare class Actor {
prop: DependsOn;
}

declare namespace Item {
// Fixed if you switch this to an interface.
type Implementation = InstanceType;
}

declare class Item {
x: DependsOn;
}

// Fixed if you remove the `SubType` generic parameter.
class ActorPTR2e extends Actor {}

// Fixed if you remove the `SubType` generic parameter.
class ItemPTR2e extends Item {}

interface DocumentClassConfig {
// Fixed if you change `typeof ActorPTR2e` to `typeof ActorPTR2e`
Actor: typeof ActorPTR2e;

// Fixed if you change `typeof ItemPTR2e` to `typeof ItemPTR2e`
Item: typeof ItemPTR2e;
}

declare class ActiveEffect extends ClientDocumentMixin(BaseActiveEffect) {
prop: number;
}

declare function ClientDocumentMixin<
// Fixed if you loosen the constraint of `BaseClass`.
BaseClass extends new (...args: any[]) => object,
>(Base: BaseClass): BaseClass;

declare class BaseActiveEffect {
constructor(...args: DependsOn);
}
```

### 🙁 Actual behavior

Numerous errors, namely:
```
Type alias 'Implementation' circularly references itself.
Type 'ActiveEffect' recursively references itself as a base type.
'ActiveEffect' is referenced directly or indirectly in its own base expression.
'args' is referenced directly or indirectly in its own type annotation.
```

### 🙂 Expected behavior

No error, as seen when you comment out the line `declare const x: InstanceType;`. The error going away indicates that this circularity is resolution order dependent.

I understand how odd the code is out of context but I did actually run into this in a real codebase.

### Additional information about the issue

_No response_

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the linked TypeScript Playground reproduction and trace the reported circular type-alias, base-type, and annotation diagnostics around InstanceType, generic class heritage, and mixin constraints. Done means the reproduction no longer reports these resolution-order-dependent errors without changing the example to avoid the circularity.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.