typescript - 编译时正常,在带有 webpack 的 typescript 中使用命名空间中的类时出现运行时错误

标签 typescript webpack swagger-codegen

我使用 swagger-codegen使用 -l typescript-angular 选项生成 REST 消费者服务库。生成的代码如下所示 (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... */
    }
}

如您所见,有些具体类需要使用,但在命名空间内声明,即不可导入。尽管缺少 import,但当我引用 API.Client.DefaultApi 时,我的编辑器 (VSCode) 没有提示,因为它将定义作为声明的命名空间的一部分认为。但在运行时,浏览器会提示 API 未定义。

我正在使用 webpack 来打包我的代码。我在 SO 上看到了一些其他问题,这些问题有点像这个问题,但没有找到那里的答案。

编辑:

根据要求,这是我的 ts 和 webpack 配置文件:

webpack 配置文件:

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/**"
  ]
}

最佳答案

您有两种选择来解决这个问题,一种是简单的,另一种是复杂的:

  1. 更改生成的 ts 文件。

在生成的代码末尾添加如下代码:

export = API.Client;

现在,您可以毫无问题地在您的模块中使用import,例如:

import {DefaultApi} from './generated-code';
  1. 但如果更改生成的文件不是一个选项,请诉诸 Salsa compiler !

想法:

使用不同的 tsconfig 拆分模块化代码而不是模块化代码。将模块化代码和非模块化代码与 Salsa、webpack 解析别名和 javascript 支持混合。

教程:

TL;DR Here a GitHub repository applying this solution.

  1. 新建tsconfig.generate.json to generated code handle,只生成代码,eg:
{
   "compilerOptions": {
      "outFile": "module-generated-code.js"
   },
   "files": ["generated-code.ts"]
}
  1. 在您的初始 tsconfig.json 中,您必须排除生成的 ts 文件。这将确保没有不必要的代码,例如:
{
   "compilerOptions": {

   },
   "exclude": ["generated-code.ts"]
}
  1. 现在,王牌已成定局!您将添加一个 api.js 文件并在您的 tsconfig.generate.json 中引用它。是的,它是一个js文件,Salsa就是在这里起作用的。为此,您必须在 tsconfig 中启用 allowJs 功能
{ 
   "compilerOptions": {
      "outFile": "module-generate-code.js", "allowJs": true
   },
   "files": ["generated-code.ts", "api.js"]
}

这些文件基本上是通过 commonjs 导出您生成的代码而无需触摸它。

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

现在,记下 tsconfig.generate.json 和您的 outFile 属性。如果您测试编译器 (tsc -p tsconfig.generate.json),您会看到所有生成的文件都连接在 module-generate-code.js 中,最后一行必须是这样的:

module.exports = API.Client;

快完成了!

现在,您可以通过import 在您自己的代码中使用module-generate-code.js!但是js文件没有最好的定义,那么你在webpack.config和tsconfig.json中配置一个resolve.alias

{ //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
        }
     },

现在您可以使用您生成的代码而无需触摸它:import api from 'api';

有任何疑问,这里是GitHub repo 使用这种方法。 希望对您有所帮助

关于typescript - 编译时正常,在带有 webpack 的 typescript 中使用命名空间中的类时出现运行时错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41277018/

相关文章:

java - Swagger Codegen 3 和 Spring HATEOAS

javascript - 迁移到 TypeScript 后 Jest 测试无法正常工作

reactjs - 使用 Webpack 代理创建 React App 中的 WebSockets

javascript - Webpack typescript 导入未定义

java - swagger-codegen-maven-plugin 在生成 API 类时忽略我为 ZonedDateTime 设置的导入映射

java - 如何在 Camel Rest 中验证请求 header

reactjs - 调度问题 "Argument of type '(调度 : Dispatch<T>) => Promise<void >' is not assignable to parameter of type ' T'.”

html - 使用 ngFor 将数据传递给嵌套组件

Angular CLI 生成的库 - 无法从其模块导入组件

webpack - 在应用内显示 vue 组件的来源