Navigation Menu

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

tslib.__extends called on undefined prototype #14734

Closed
jsayol opened this issue Mar 19, 2017 · 15 comments
Closed

tslib.__extends called on undefined prototype #14734

jsayol opened this issue Mar 19, 2017 · 15 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@jsayol
Copy link

jsayol commented Mar 19, 2017

TypeScript Version: 2.2.1

Code
To make things simple, here's a repo to easily reproduce this: https://github.com/jsayol/typescript-issue-14734

$ git clone https://github.com/jsayol/typescript-issue-14734.git
$ cd typescript-issue-14734
$ npm install
$ npm run build

And load index.html in the browser.

a.ts:
import { B } from './b';

export class A {
  constructor(public prop: string) {
  }

  b(): B {
    return new B(this.prop, 123);
  }

  log() {
    console.log(`Prop: ${this.prop}`);
  }
}
b.ts
import { A } from './a';

export class B extends A {
  constructor(prop: string, public otherStuff: number) {
    super(`B ${prop}`);
  }
}
index.ts
import { A } from './a';
import { B } from './b';

const a = new A('hello');
const b: B = a.b();
b.log();

Expected behavior:
Seeing "B hello" logged in the console.

For reference, putting all the code in a single file generates the correct output:

class A {
  constructor(public prop: string) {
  }

  b(): B {
    return new B(this.prop, 123);
  }

  log() {
    console.log(`Prop: ${this.prop}`);
  }
}

class B extends A {
  constructor(prop: string, public otherStuff: number) {
    super(`B ${prop}`);
  }
}

const a = new A('hello');
const b: B = a.b();
b.log();

Actual behavior:

tslib.es6.js:22 Uncaught TypeError: Object prototype may only be an Object or null: undefined
    at setPrototypeOf (<anonymous>)
    at Object.__extends [as a] (tslib.es6.js:22)
    at b.js:4
    at Object.__webpack_exports__.a (b.js:11)
    at __webpack_require__ (bootstrap 4672cf4…:19)
    at Object.defineProperty.value (bootstrap 4672cf4…:65)
    at __webpack_require__ (bootstrap 4672cf4…:19)
    at Object.<anonymous> (bundle.umd.js:108)
    at __webpack_require__ (bootstrap 4672cf4…:19)
    at Object.<anonymous> (bundle.umd.js:321)

This is the generated b.js, where the problem is:

import * as tslib_1 from "tslib";
import { A } from './a';
var B = (function (_super) {
    tslib_1.__extends(B, _super); // <--- Exception thrown here. "B" is undefined.
    function B(prop, otherStuff) {
        var _this = _super.call(this, "B " + prop) || this;
        _this.otherStuff = otherStuff;
        return _this;
    }
    return B;
}(A));
export { B };
//# sourceMappingURL=b.js.map
@jsayol jsayol changed the title __extends called on undefined prototype tslib.__extends called on undefined prototype Mar 19, 2017
@jsayol
Copy link
Author

jsayol commented Mar 19, 2017

Possibly related: #10837 and #5207

@kitsonk
Copy link
Contributor

kitsonk commented Mar 20, 2017

You are dealing with a circular dependency. TypeScript can statically identify the shape of everything, therefore it is fine, but it seems WebPack (you module loader of choice) is not resolving the circular dependency effectively at runtime. I suspect that WebPack is attempting to instantiate module B before module A is ready, therefore module B can be loaded properly.

When they are in the same module, B isn't technically required by A until a certain method is called, therefore everything is resolved fine.

@jsayol
Copy link
Author

jsayol commented Mar 20, 2017

Thanks @kitsonk, makes sense. I wasn't sure at first if this was a TypeScript or Webpack issue. I'll move this over there and close it here for now.

@kbtz
Copy link

kbtz commented Jun 29, 2017

I'd like to add to @kitsonk's excellent explanation that you might be able to workaround this by changing the export order of some of your barrels/modules.

I can't explain it well in generic terms since it really depends on how you organized your barrels and where your webpack entry points are, but a good rule of thumb would be to always export higher level classes at the bottom and its dependencies at the top.

@jsayol
Copy link
Author

jsayol commented Jun 29, 2017

Thanks for your imput @cvsguimaraes. In the end it all came down to the fact that TypeScript assumes that module imports do not have side effects.

See here for more info: webpack/webpack#4520 (comment)

Supamiu added a commit to kaiu-lab/serializer that referenced this issue Jun 30, 2017
@304NotModified
Copy link

Hi,

We have the same error. Currently it is difficult to find the cycle and I was hoping this could be fixed or the error could be improved.

But it's unclear to me if this is now a Webpack or typescript issue? (it's closed on both repos)

@kbtz
Copy link

kbtz commented Jul 14, 2017

But it's unclear to me if this is now a Webpack or typescript issue? (it's closed on both repos)

@304NotModified See this comment from webpack author on the issue.

@kodeine
Copy link

kodeine commented Jul 31, 2017

i am facing the same issue and cant find exact root cause of this error.

@kitsonk
Copy link
Contributor

kitsonk commented Jul 31, 2017

As stated in the comment that @cvsguimaraes linked to, this isn't either a TypeScript or WebPack issue. It is an effect of how ES6 modules are parsed.

Circular dependencies will be your downfall and arguably a bad design decision. They are fragile. TypeScript is not disallowing it, which I guess would be the only argument, in that when you have an import order issue that cannot be resolved.

@kodeine
Copy link

kodeine commented Jul 31, 2017

@kitsonk all i am doing is extending classes to base api class. Does this mean i should change the code and not use class extends?

@kitsonk
Copy link
Contributor

kitsonk commented Jul 31, 2017

This particular issue has to do with circular references, where A.ts depends on B.ts which depends on A.ts.

all i am doing is extending classes to base api class

Clearly that can' be the case, if you are encountering this issue.

@kodeine
Copy link

kodeine commented Jul 31, 2017

What would be the way to fix it ? change the imports or not use extend and use it as

private api: BaseApi = new BaseApi();

@kitsonk
Copy link
Contributor

kitsonk commented Jul 31, 2017

You are giving one line of code and saying how do I fix it? when you have even indicated what the problem is. The code you are quoting doesn't even reference the code at the top of this issue.

You should be asking "how do I" questions on Gitter or StackOverflow, providing an appropriate level of information on what the problem is.

@kodeine
Copy link

kodeine commented Jul 31, 2017

So i am extending providers with base api provider.

HistoryRequestProvider is one of the provider extending to ApiService. there are around 10+ providers which extend to ApiService.

import {Injectable} from '@angular/core';
import {AuthHttp} from 'angular2-jwt';
import {Request} from "./models/request.model";
import {EventService} from "../../services/event.service";
import {ApiService} from "../../services/base.service";
import {Observable} from "rxjs";

@Injectable()
export class HistoryRequestProvider extends ApiService<Request> {
    protected model = Request;
    protected endpoint: string = 'me/requests/history';

    constructor(protected auth:AuthHttp, protected events:EventService) {
        super();
    }
}
export abstract class ApiService<T extends GenericMayHaveId> extends ApiHelper<T> {
    protected baseUrl: string = Config.apiUrl;
    protected dataStore: DataStore<any> = new DataStore();
    protected ram: DataStore<any> = new DataStore();
    protected activeStore: string;

    protected endpoint: string;
    protected auth: AuthHttp;
    protected events: EventService;
}
export interface GenericMayHaveId {
    id?: number|string;
    updated_at?: Date|DateTime;
    created_at?: Date|DateTime;
}
export abstract class ApiHelper<T> {
    protected contentHeader: Headers = new Headers(
        Object.assign(apiVersionHeader, {"Content-Type": "application/json"})
    );
    protected events: EventService;
    protected initiated: boolean;

    getActiveStore(): any {
    }
}

and this is the error i get

image

image

listing all providers.
image

@microsoft microsoft locked and limited conversation to collaborators Jul 31, 2017
@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Jul 31, 2017

The issue tracker is for tracking issues with TypeScript itself, not issues with user code.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

7 participants