microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.02k stars 12.49k forks source link

Code transpilation does not work with any target later than es5. #51801

Open WillooWisp opened 1 year ago

WillooWisp commented 1 year ago

Bug Report

Typescript transpiles the attached code into something not possible to execute in browser, when targeting later versions than es5.

ng_reflect.ts:24
ERROR TypeError: X is not a constructor at e.t (oidc-client.min.js:1:12082) at new e (oidc-client.min.js:49:27046) at new e (oidc-client.min.js:49:9187) at new AppComponent (app.component.ts? [sm]:51:25) at NodeInjectorFactory.AppComponent_Factory [as factory] (app.component.ts? [sm]:52:2) at getNodeInjectable (di.ts:642:17) at createRootComponent (component_ref.ts:426:4) at ComponentFactory.create (component_ref.ts:262:10) at ApplicationRef.bootstrap (application_ref.ts:1126:4) at eval (application_ref.ts:623:1)

🔎 Search Terms

Transpile, error, es5, es2015

🕗 Version & Regression Information

I started seeing this problem today, when I updated from angular 13 to 14 and typescript transpile target was changed in tsconfig from es5 to es2020, but the problem seems to exist from es6 and forward.

⏯ Playground Link

Changing from target "ES2015" to "ES5", in tsconfig, makes it transpile correctly for browser to execute. https://stackblitz.com/edit/angular-ivy-qlrq14

💻 Code

https://stackblitz.com/edit/angular-ivy-qlrq14

class ResponseValidatorCtor {
  private _settings: any;

  constructor(
    settings,
    metadataServiceCtor?: MetadataServiceCtor,
    userInfoServiceCtor?: any
  ) {
    this._settings = settings;
  }

  public validateSigninResponse(state, response) {
    response.state = state._data;
    return response;
  }

  public validateSignoutResponse(state, response) {
    // validation goes here
    return Promise.resolve(response);
  }
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  private userManagerSettings: UserManagerSettings = {
    ResponseValidatorCtor: (settings, metadata, userInfo) =>
      new ResponseValidatorCtor(settings),
    authority: 'https://login.microsoftonline.com/common/v2.0',
    client_id: '',
    redirect_uri: `${window.location.origin}/login/oidc/azure`,
    silent_redirect_uri: `${window.location.origin}/login/oidc/azure`,
    post_logout_redirect_uri: `${window.location.origin}/login`,
    response_type: 'id_token',
    scope: 'openid email profile',
  };
  private userManager = new UserManager(this.userManagerSettings);
}

🙁 Actual behavior

Website fails loading due to error in code.

🙂 Expected behavior

Expects website to load without failures.

MartinJohns commented 1 year ago

This seems to be an issue with Angular or OIDC, not with TypeScript.

WillooWisp commented 1 year ago

@MartinJohns You might be right, but to me it feels like an issue with Typescript since the only change done from working to non-working is change of target from es5 to something later, e.g. es2015. Isn't that a hint that it gets transpiled differently and incorrectly?

Why should it be a problem with angular or the oidc client when it works targeting es5?

MartinJohns commented 1 year ago

A brief look at the generated source for your TypeScript files it looked correctly. But in the end you're not using TypeScript to compile your code, you're using Angular for it. Angular hijacks the TypeScript compiler API and does a whole lot of mumbo jumbo around it, including bundling, and your error appears in the "oidc-client.min.js" file (which the TypeScript compiler does not generate). So I suspect something goes wrong when creating the bundle.

RyanCavanaugh commented 1 year ago

To look at this we'd need a repro that doesn't involve Angular, alongside an actual "This line in particular is wrong and should be this other thing instead" statement. People have been using > ES5 class transforms for 8+ years without issue so the burden of proof is entirely on the position that it's never worked.

WillooWisp commented 1 year ago

Okay, I understand, I will try to make a reproduction without angular then.

/ Joel Fjordén


From: Martin Johns @.> Sent: Wednesday, December 7, 2022 6:15:07 PM To: microsoft/TypeScript @.> Cc: Joel Fjordén @.>; Author @.> Subject: Re: [microsoft/TypeScript] Code transpilation does not work with any target later than es5. (Issue #51801)

A brief look at the generated source for your TypeScript files it looked correctly. But in the end you're not using TypeScript to compile your code, you're using Angular for it. Angular hijacks the TypeScript compiler API and does a whole lot of mumbo jumbo around it, including bundling, and your error appears in the "oidc-client.min.js" file (which the TypeScript compiler does not generate). So I suspect something goes wrong when creating the bundle.

— Reply to this email directly, view it on GitHubhttps://github.com/microsoft/TypeScript/issues/51801#issuecomment-1341300713, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AAZEZZKOGRHUZNA6AZT5XEDWMDAZXANCNFSM6AAAAAASWY5KBY. You are receiving this because you authored the thread.Message ID: @.***>

WillooWisp commented 1 year ago

@MartinJohns and @RyanCavanaugh here is a clean TypeScript sample illustrating the same problem, where it works targeting ES5, but not anything above.

https://stackblitz.com/edit/typescript-acmvrk

The transpile problem seems to be when setting the ResponseValidatorCtor property of UserManagerSettings. Maybe you can see a workaround to how the code can be written for the transpile to work above ES5 as target?

MartinJohns commented 1 year ago

The types provided by your library are wrong. This code works fine: ResponseValidatorCtor: ResponseValidatorCtor

When targeting ES5 or earlier your class will transpile to a function, because ES5 and earlier does not support classes. When targeting later your class will remain a class in the JavaScript output. Whatever the reason, your oidc library can't handle classes and errors.

TypeScript behaves correctly here.

RyanCavanaugh commented 1 year ago

Again, you'll need to tell me which line of code in the generated output is wrong, and why.