Kompileringstid OK, kjøretidsfeil ved bruk av klasse fra namespace i TypeScript med Webpack


Jeg bruker swagger-codegen med -l typescript-angular-alternativet for å generere et bibliotek av REST-forbrukertjenester. Den genererte koden ser slik ut (DefaultApi.ts):

namespace API.Client {
    'use strict';

    export class DefaultApi {
        protected basePath = 'http://localhost:7331/v1';
        public defaultHeaders : any = {};

        static $inject: string[] = ['$http', '$httpParamSerializer', 'basePath'];

        constructor(protected $http: ng.IHttpService, protected $httpParamSerializer?: (d: any) => any, basePath?: string) {
            if (basePath !== undefined) {
                this.basePath = basePath;
            }
        }

        private extendObj<T1,T2>(objA: T1, objB: T2) {
            for(let key in objB){
                if(objB.hasOwnProperty(key)){
                    objA[key] = objB[key];
                }
            }
            return <T1&T2>objA;
        }

        /**
         * Delete a person.
         * Deletes a specified individual and all of that person&#39;s connections. 
         * @param id The id of the person to delete
         */
        public deletePersonById (id: number, extraHttpRequestParams?: any ) : ng.IHttpPromise<{}> {/*...*/}

        /* etc... */
    }
}

Som du kan se, finnes det konkrete klasser som må brukes, men som er deklarert inne i et namespace, altså ikke importerbare. Min editor (VSCode) klager ikke når jeg refererer til API.Client.DefaultApi til tross for mangelen på et import, fordi den antar jeg plukker opp definisjonen som en del av et deklarert namespace. Men under kjøring klager nettleseren over at API ikke er definert.

Jeg bruker webpack for å pakke koden min. Jeg ser noen få andre spørsmål på SO som ligner på dette, men hadde ingen hell med svarene der.

REDIGER :

Som forespurt, her er mine konfigurasjonsfiler for ts og webpack:

webpack-konfigurasjonsfil:

const webpack = require('webpack');
const conf = require('./gulp.conf');
const path = require('path');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const autoprefixer = require('autoprefixer');

module.exports = {
  module: {
    preLoaders: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loader: 'tslint'
      }
    ],

    loaders: [
      {
        test: /.json$/,
        loaders: [
          'json'
        ]
      },
      {
        test: /\.(css|less)$/,
        loaders: [
          'style',
          'css',
          'less',
          'postcss'
        ]
      },
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        loaders: [
          'ng-annotate',
          'ts'
        ]
      },
      {
        test: /.html$/,
        loaders: [
          'html'
        ]
      }
    ]
  },
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.NoErrorsPlugin(),
    new HtmlWebpackPlugin({
      template: conf.path.src('index.html')
    })
  ],
  postcss: () => [autoprefixer],
  debug: true,
  devtool: 'source-map',
  output: {
    path: path.join(process.cwd(), conf.paths.tmp),
    filename: 'index.js'
  },
  resolve: {
    modules: [
      path.resolve(__dirname, '../src/app'),
      path.resolve(__dirname, '../node_modules')
    ],
    extensions: [
      '',
      '.webpack.js',
      '.web.js',
      '.js',
      '.ts'
    ]
  },
  entry: `./${conf.path.src('index')}`,
  ts: {
    configFileName: '../tsconfig.json'
  },
  tslint: {
    configuration: require('../tslint.json')
  }
};

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "src/app",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "module": "commonjs"
  },
  "compileOnSave": false,
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "!typings/**",
    "!node_modules/**"
  ]
}

Svar #1

Du har to alternativer for å fikse dette, en enkel og en annen kompleks:

  1. endre generert ts-fil.

Legg til følgende kode på slutten av den genererte koden:

export = API.Client;

Nå kan du bruke import i modulene dine uten problemer, f.eks:

import {DefaultApi} from './generated-code';
  1. Men hvis det ikke er et alternativ å endre generert fil, appeller til Salsa-kompilatoren!

Ideen:

Del den modulære koden og ikke-modulære koden med forskjellige tsconfig. Bland modulær kode og ikke-modulær med Salsa, webpack resolve alias og JavaScript-støtte.

Veiledning:

TL;DR Her er et GitHub-repositorium som bruker denne løsningen.

  1. Opprett en ny tsconfig.generate.json for å håndtere generert kode, bare generert kode, f.eks:
{
   "compilerOptions": {
      "outFile": "module-generated-code.js"
   },
   "files": ["generated-code.ts"]
}
  1. i din opprinnelige tsconfig.json må du utelate genererte ts-filer. Dette vil sikre at det ikke finnes unødvendig kode, f.eks:
{
   "compilerOptions": {

   },
   "exclude": ["generated-code.ts"]
}
  1. Nå, esset i ermet! Du vil legge til en api.js-fil og referere til den i din tsconfig.generate.json. Ja, det er en js-fil, det er her Salsa kommer i aksjon. Og for å gjøre dette må du aktivere allowJs-funksjonen i tsconfig
{ 
   "compilerOptions": {
      "outFile": "module-generate-code.js", "allowJs": true
   },
   "files": ["generated-code.ts", "api.js"]
}

Disse filene er i utgangspunktet for å eksportere din genererte kode via CommonJS uten å røre den.

/// <reference path="./namespacing-code.ts" />
// typescript compiler don't warning this because is Salsa!
module.exports = API.Client;

Merk nå i tsconfig.generate.json og din outFile-egenskap. Hvis du tester kompilatoren (tsc -p tsconfig.generate.json), ser du alle dine genererte filer satt sammen i module-generate-code.js, og den siste linjen må være som i dette:

module.exports = API.Client;

Nesten ferdig!

Nå kan du bruke module-generate-code.js i din egen kode med import! Men hvis js-filer ikke har de beste definisjonene, må du konfigurere en resolve.alias i webpack.config og tsconfig.json

{ //webpack.config
    resolve: {
      extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'],
      alias:{ 'api':'./module-generated-code.js'
    }
}
{ //tsconfig.json
    "compilerOptions": {
        "allowJs": true, //remember of enabling Salsa here too
        "baseUrl": ".",
        "paths": {
            "api":["api.js"] //it is just get type definitions from generated files
        }
     },

Nå kan du bruke koden du har generert uten å røre den: import api from 'api';

Hvis det er noen tvil, her er et GitHub-repo som bruker denne tilnærmingen. Jeg håper jeg har hjulpet

Svar #2

Den nåværende versjonen av swagger-codegen TypeScript Angular-generatoren pakker ikke DefaultApi inn i et navnrom.

Oppdater og generer på nytt. Gi meg beskjed hvis du har noen problemer.

Relaterte artikler