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

Regression: bug in emitted declarations involving branded types since 5.1 #54655

Closed
GabeAtWork opened this issue Jun 15, 2023 · 6 comments · Fixed by #57275
Closed

Regression: bug in emitted declarations involving branded types since 5.1 #54655

GabeAtWork opened this issue Jun 15, 2023 · 6 comments · Fixed by #57275
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@GabeAtWork
Copy link

GabeAtWork commented Jun 15, 2023

Bug Report

Code that used to compile fine in 5.0.0 now produces invalid declarations with type names suffixed in _1 which are not defined (see code below).

🔎 Search Terms

Branded type, suffix, emit

🕗 Version & Regression Information

  • This changed between versions 5.0.0 and 5.1.3

⏯ Playground Link

Playground link with relevant code

💻 Code

// A simple branded type definition
export type Brand<
  Base,
  Branding,
  ReservedName extends string = "__type__"
> = Base & { [K in ReservedName]: Branding } & { __witness__: Base };

// Defining a branded type
export type BoundedInteger<
  LowerBound extends number,
  UpperBound extends number
> = Brand<number, "BoundedInteger">;

// Using in in a function
export const toBoundedInteger =
  <LowerBound extends number, UpperBound extends number>(bounds: {
    lowerBound: LowerBound;
    upperBound: UpperBound;
  }) =>
  (
    n: number
  ): BoundedInteger<LowerBound, UpperBound> =>
  // Implementation doesn't matter here
    ({} as any)

🙁 Actual behavior

// v5.1.3
// in D.TS

export type Brand<Base, Branding, ReservedName extends string = "__type__"> = Base & {
    [K in ReservedName]: Branding;
} & {
    __witness__: Base;
};
export type BoundedInteger<LowerBound extends number, UpperBound extends number> = Brand<number, "BoundedInteger">;
export declare const toBoundedInteger: <LowerBound extends number, UpperBound extends number>(bounds: {
    lowerBound: LowerBound;
    upperBound: UpperBound;
// ❌ Cannot find name 'LowerBound_1'. Did you mean 'LowerBound'?
}) => (n: number) => BoundedInteger<LowerBound_1, UpperBound_1>;
// 👆 This line

🙂 Expected behavior

// v5.0.4
// in D.TS

export type Brand<Base, Branding, ReservedName extends string = "__type__"> = Base & {
    [K in ReservedName]: Branding;
} & {
    __witness__: Base;
};
export type BoundedInteger<LowerBound extends number, UpperBound extends number> = Brand<number, "BoundedInteger">;
export declare const toBoundedInteger: <LowerBound extends number, UpperBound extends number>(bounds: {
    lowerBound: LowerBound;
    upperBound: UpperBound;
}) => (n: number) => BoundedInteger<LowerBound, UpperBound>;
// 👆 This line
@fatcerberus
Copy link

I'm confused as to why there are type annotations in "compiled" code, in any TS version. Even your Playground shows that the compiled JS code is:

export const toBoundedInteger = (bounds) => (n) => 
// Implementation doesn't matter here
({});

@GabeAtWork
Copy link
Author

@fatcerberus in the playground, you can see the definitions in the D.TS tab:
image

Those definitions are exported in the emitted code so that TS code that imports from this compiled code (e.g. when this is a library) can have the proper types.

So for instance, I could emit the .js code along with the .d.ts code of this library which would enable me to import the type BoundedInteger from another project's code as well as having toBoundedInteger have proper types instead of any.

@fatcerberus
Copy link

Ah, you meant the .d.ts. When you say "invalid compiled code" that makes it sound like you mean the output JS. If you had said "invalid type definitions" or "invalid declarations" that would have been clearer.

@GabeAtWork GabeAtWork changed the title Definition type bug in branded types since 5.1 Declaration bug in branded types since 5.1 Jun 15, 2023
@GabeAtWork
Copy link
Author

@fatcerberus good point, I've updated the issue description to hopefully clarify that, thanks for the feedback 🙏

@GabeAtWork GabeAtWork changed the title Declaration bug in branded types since 5.1 Bug in emitted declarations involving branded types since 5.1 Jun 15, 2023
@GabeAtWork GabeAtWork changed the title Bug in emitted declarations involving branded types since 5.1 Regression: bug in emitted declarations involving branded types since 5.1 Jun 19, 2023
@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Jun 19, 2023
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 5.2.0 milestone Jun 19, 2023
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label Jun 29, 2023
@GabeAtWork
Copy link
Author

Any news on this topic? The fix seems has been available since June, anything I can help with to help get it merged?

@jakebailey
Copy link
Member

Using the original playground link, it looks like this bug is fixed in nightly.

I bisected and figured out that I fixed it in #55820... 😅

I'll send a PR to add a test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
6 participants