swagger-api / swagger-codegen

swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.
http://swagger.io
Apache License 2.0
17.07k stars 6.03k forks source link

[Angular2 TypeScript] Query parameters: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter. #5482

Open babolivier opened 7 years ago

babolivier commented 7 years ago
Description

Hi. I've started writing an API for a school project recently, and am using codegen to generate a client for my team-mate who is developping it using Angular2.

One of our first route uses number parameters. When compiling the whole thing, an error pops up:

error TS2358: The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.

After reading the code codegen generated, it seems that this part is causing it:

public getV1ClientPostsWithHttpInfo(start?: number, nb?: number, from?: number, to?: number, extraHttpRequestParams?: any): Observable<Response> {
    const path = this.basePath + `/v1/client/posts`;

    let queryParameters = new URLSearchParams();
    let headers = new Headers(this.defaultHeaders.toJSON()); // https://github.com/angular/angular/issues/6845
    if (start !== undefined) {
        if(start instanceof Date) {
            queryParameters.set('start', <any>start.d.toISOString());
        } else {
            queryParameters.set('start', <any>start);
        }
    }

I didn't include it in my paste, but the three remaining parameters get the same check.

The fails occurs at the if(start instanceof Date) part (and frankly I don't get why this check is performed, as there's no way a number type can be instance of Date).

Edit: After further research, it seems that only query params get this check (as described here).

Swagger-codegen version

Dunno if that's a regression as it's my first time using codegen. The version I'm using is 2.2.2.

Swagger declaration file content or url

Here's the route that's causing trouble: https://gist.github.com/babolivier/2afd8207502c5ef498c0f7ca902d165a#file-swagger-json-L76-L126

This JSON file was generated by hapi-swagger

Command line used for generation
java -jar swagger-codegen-cli.jar generate -i http://127.0.0.1:3000/swagger.json -l typescript-angular2
Steps to reproduce
Related issues

Searched for one, came empty-handed.

Suggest a Fix

I don't know codegen's codebase enough to think of a fix. However, this instanceof is clearly unecessary and should be removed as it's causing the code not to compile.

babolivier commented 7 years ago

Just built swagger-codegen from the 2.3.0 branch, and it now works correctly.

martinmcwhorter commented 7 years ago

Just built the 2.3.0 snapshot and it does look like this issue is sorted -- unfortunately this uses the InjectionToken in Angular4 -- our project is still using Angular2.

OpaqueTokens are still supported with Angular4 -- does it make sense to still use them and support Angular2?

I would be happy to submit a pull request if this is the case.

The benefit of InjectionToken being that it is typed, though in this case the type is a primitive string.

Tmin10 commented 7 years ago

I build project with latest 2.3.0 snapshot but have compilation error in string import { InjectionToken<string> } from '@angular/core';:


ERROR in .../variables.ts (1,33): Expression expected.
ERROR in .../variables.ts (1,40): ';' expected.
ERROR in .../variables.ts (1,24): String literal expected.
ERROR in .../variables.ts (1,35): Cannot find name 'from'.

I use latest angular 4.
martinmcwhorter commented 7 years ago

I have created a pull request that replaces the InjectorToken (added in Angular v4) with an Angular v2 supported OpaqueToken. #5829

fluffybonkers commented 7 years ago

Does anyone know why, even in Angular 4, InjectionToken is not working?

I am having the same problem as @Tmin10 and in addition getting the error You may need an appropriate loader to handle this file type. from Webpack, I think.

Tmin10 commented 7 years ago

We have the same issue with InjectionToken problem: #5709

Wolfium commented 7 years ago

I need a jar binary with the fix in the short time, and I don't have too much time to spend searching, copying and configuring own template using original ones for typescript-angular2. Is there any url where I can get the any 2.3.0 snapshot or not to get it fix it in a slick way?

By the way, I did a google research and it was impossible to get any above official 2.2.#.

Thanks in advance for any help Regards

Wolfium commented 7 years ago

In the meantime (just figured out) will try going downgrading until get a working version.

macjohnny commented 7 years ago

@babolivier this issue should be resolved with the current master. can you check that and close this issue?

pablosaracusti commented 7 years ago

I had the same issue in the following code using Angular 5:

handleError(error: Error, exceptionHalt = true): ErrorObservable {
    if ((error instanceof DisconnectedError) || (error instanceof Exception)) {
      // Workaround for Cannot instantiate cyclic dependency! error.
      this.logger = this.injector.get(NGXLogger);
      this.logger.error('An error occurred', error);

      if ((error instanceof DisconnectedError)) {
        this.disconnected(error);
      } else if ((error instanceof Exception) && exceptionHalt) {
        this.messageService.show(CONFIG.labels.error, error.message, 'EXC', true);
      }
    }

    return Observable.throw(error);
  }

Typescript complained about the last error instanceof Exception by marking the error parameter as type of "never". However, I still was able to compile and my application was working.

I can suggest a workaround that works for me: Try to put the instanceof checking inside a boolean variable and then perform the if check, like this:

handleError(error: Error, exceptionHalt = true): ErrorObservable {
    const isDisconnected = (error instanceof DisconnectedError);
    const isException = (error instanceof Exception);

    if (isDisconnected || isException) {
      // Workaround for Cannot instantiate cyclic dependency! error.
      this.logger = this.injector.get(NGXLogger);
      this.logger.error('An error occurred', error);

      if (isDisconnected) {
        this.disconnected(error);
      } else if (isException && exceptionHalt) {
        this.messageService.show(CONFIG.labels.error, error.message, 'EXC', true);
      }
    }

    return Observable.throw(error);
  }

I hope this can help you solve your problem.