Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tsc reports error when a recursive type alias defines a finite type. #33922

Closed
vczh opened this issue Oct 10, 2019 · 4 comments
Closed

tsc reports error when a recursive type alias defines a finite type. #33922

vczh opened this issue Oct 10, 2019 · 4 comments
Labels
Duplicate An existing issue was already created

Comments

@vczh
Copy link

vczh commented Oct 10, 2019

TypeScript Version: 3.4.0-dev.201xxxxx

Search Terms:

Code

Before pasting the code that makes tsc prompt compiler errors, please allow me to explain my scenario.

I am making an AST for a language, let's say it looks like this:

export interface Stop {
    kind: 'Stop';
}

export interface Unary {
    kind: 'Unary';
    x: Expr;
}

export interface Binary {
    kind: 'Binary';
    x: Expr;
    y: Expr;
}

export interface SugaredExpr {
    kind: 'SugaredExpr';
    x: Expr;
    y: Expr;
    z: Expr;
}

export type Expr = Stop | Unary | Binary | SugaredExpr;

Before compiling the code, I have a function called desugar, which transforms SugaredExpr to the combination of others, so the output looks like this:

export interface Stop {
    kind: 'Stop';
}

export interface Unary {
    kind: 'Unary';
    x: Expr;
}

export interface Binary {
    kind: 'Binary';
    x: Expr;
    y: Expr;
}

export type Expr = Stop | Unary | Binary;

Now I want to describe the type of desugar in an accurate way without violating the DRY principal, so I write the following code:

export interface Stop {
    kind: 'Stop';
}

export interface Unary<T> {
    kind: 'Unary';
    x: T;
}

export interface Binary<T> {
    kind: 'Binary';
    x: T;
    y: T;
}

export interface SugaredExpr {
    kind: 'SugaredExpr';
    x: ExprWithSugar;
    y: ExprWithSugar;
    z: ExprWithSugar;
}

export type ExprWithSugar = Stop | Unary<ExprWithSugar> | Binary<ExprWithSugar> | SugaredExpr;
export type Expr = Stop | Unary<Expr> | Binary<Expr>;

export function desugar(exprWithSugar: ExprWithSugar): Expr {
    throw new Error('Not Implemented');
}

T becomes the AST category. You pass union types of chosen ASTs, so that ExprWithSugar could be a Unary with SugaredExpr inside, but Expr could not.

Expected behavior: It compiles

Actual behavior:
Type alias 'ExprWithSugar' circularly references itself.ts(2456)
Type alias 'Expr' circularly references itself.ts(2456)

Obviously both ExprWithSugar and Expr should correct, because Stop ensures that the recursion is not infinite.

Related Issues: This is about recursive type alias. I searched and see some issues, but all of them seems incorrect. And I believe I am making a valid one.

@jack-williams
Copy link
Collaborator

If you search "recursive type aliases" you get this PR in first few hits: #33050. It was merged recently and enables this scenario for 3.7. You can try it out in the beta here.

@vczh
Copy link
Author

vczh commented Oct 11, 2019

@jack-williams Cool! Do you have a road map about when 3.7 will be available from npm?

@jack-williams
Copy link
Collaborator

#33352

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Oct 17, 2019
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants