TypeScript
TypeScript copied to clipboard
Type alias circularly references itself
🔎 Search Terms
circular reference, generic, error TS2456, recursive
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about circular reference
⏯ Playground Link
https://www.typescriptlang.org/play/?ts=5.8.2#code/C4TwDgpgBAYg9nAKuaBeKBvAsAKClAMwQH4AuKAIwQBsIBDAOwG5cBfFnXUSKAIToDOEAKK0AthAbAAPIgB8UdPCQooAMky58AYwAWAS2oATAE6TyAYQCuA4HDGiIEqQG0Auh3zcI5RB3a4XKrWtvaOzsCKfIIi4pIyAOS6AIwJchxAA
💻 Code
type FooType = {
foo?: boolean;
};
type BaseElement<T> = FooType & {
children: CustomElement[];
type: T;
};
type CustomElement = BaseElement<'h1'>;
🙁 Actual behavior
When defining a recursive type structure using a generic type, TypeScript incorrectly reports a Type alias 'CustomElement' circularly references itself.(2456) error, even though the type should be resolvable.
It gets weird when you move type: T; line above the children: CustomElement[]; and the error disappears. Also removing FooType will resolve the issue.
🙂 Expected behavior
In the first place the code should not throw any errors, in the second place the behavior should not change by reordering records of a type.
Additional information about the issue
No response
No responses so far, so I'll take a stab at this. The first thing you'll want to read is this FAQ entry: https://github.com/microsoft/TypeScript/wiki/FAQ#circularity-errors-may-occur-in-the-presence-of-circularities.
The type you've given here is obviously circular. And while the Typescript compiler can resolve circularities in many simple cases, so that useful things like recursive tree types can exist, it's not guaranteed to be able to do that in every arbitrary case of intersections, generic instantiations, and other manipulations. It's also not a defect just because certain rearrangements make the type resolve (that's straight out of the FAQ). And this one is not a regression since it's been like that since at least 3.3.
I can't say for sure whether the Typescript team is interested in changing the behavior in this case, but all signs point to it being a low priority at best.
Hi @nmain,
So this is actually a bug but Typescript team has no plan to fix it any soon?
It's not a bug per se, and it's probably virtually impossible to come up with a solution that will accept any definition that can be construed as valid. That said, with circularities, you can usually rejigger them until the error goes away. For instance, this seems to work fine:
type FooType = {
foo?: boolean;
};
interface BaseElement<T> extends FooType {
children: CustomElement[];
type: T;
};
type CustomElement = BaseElement<'h1'>;
@snarbles2 I'm aware of ways to fix this issue as I mentioned in the issue:
It gets weird when you move
type: T;line above thechildren: CustomElement[];and the error disappears.
I think something should be implemented to make circular references behave more predictably to save developers from wasting time. I'm also willing to help fix this issue (at least the rearrangement issue).
Ah, sorry. Reading comprehension fail.
I think something should be implemented to make circular references behave more predictably to save developers from wasting time.
"more predictable" here generally means "error more", we already want to error less. PRs welcomed for sure.