In attempting to produce a reasonable facsimile of the desired PathIn type from #23398, I ran into this issue with the block on circular type references that I don't think has a workaround, unlike previous issues raised on the subject. #14174 seems closest, and the discussion there identified a related use-case for allowing circular references on types, but I think it makes more sense to raise these concerns as a separate issue rather than extend that discussion (which isn't that closely related to the original issue anyway).
The issue, in short, is that types cannot handle circular references, while classes and interfaces (which can) don't support distribution over a union or being a union.
TypeScript Version: 2.9.0-dev.20180412
Search Terms: circular reference
Code
(strange type Blah<A extends string> = A extends string ? /*...*/ : never; used to force distribution)
type PathBase<A extends string> = A extends string ? {
node: A;
}: never;
export type Leaf<A extends string> = A extends string ? {
kind: 'leaf';
node: A;
}: never;
export type Branch<A extends string, B extends PathBase<string>> = A extends string ? {
kind: 'branch',
node: A;
next: B;
}: never;
export type PathIn<Obj extends {}> =
/* ^^^^^^
[ts] Type alias 'PathIn' circularly references itself. */
Obj[keyof Obj] extends {}
? Leaf<keyof Obj> | Branch<keyof Obj, PathIn<Obj[keyof Obj]>>
/* ^^^^^^^^^^^^^^^^^^^^^^
[ts] Type 'PathIn' is not generic. */
: Leaf<keyof Obj>;
Expected behavior:
Compiles without error. PathIn produces a wild and crazy union of linked lists using Leaf and Branch for every path in Obj.
Actual behavior:
Type alias 'PathIn' circularly references itself.
Related Issues: #14174, #23398
In attempting to produce a reasonable facsimile of the desired
PathIntype from #23398, I ran into this issue with the block on circular type references that I don't think has a workaround, unlike previous issues raised on the subject. #14174 seems closest, and the discussion there identified a related use-case for allowing circular references on types, but I think it makes more sense to raise these concerns as a separate issue rather than extend that discussion (which isn't that closely related to the original issue anyway).The issue, in short, is that types cannot handle circular references, while classes and interfaces (which can) don't support distribution over a union or being a union.
TypeScript Version: 2.9.0-dev.20180412
Search Terms: circular reference
Code
(strange
type Blah<A extends string> = A extends string ? /*...*/ : never;used to force distribution)Expected behavior:
Compiles without error.
PathInproduces a wild and crazy union of linked lists usingLeafandBranchfor every path inObj.Actual behavior:
Type alias 'PathIn' circularly references itself.Related Issues: #14174, #23398