【问题标题】:RxJS Incompatible Type with TypescriptRxJS 类型与 Typescript 不兼容
【发布时间】:2020-06-30 22:14:34
【问题描述】:

我正在使用两个存储库,分别称为 web-commonA-frontend。我通常来自A-frontendnpm link web-common。两者都有几个相同的依赖项,React、Typescript、Google Maps、MobX 等。我从来没有遇到过这个工作流程的问题。当我添加 RxJS 时,我开始收到类似这样的错误:

TS2345: Argument of type 'import("/Users/fharvey/code/monolith/A-frontend/node_modules/rxjs/internal/types").OperatorFunction<import("/Users/fharvey/code/monolith/web-common/services/scaffold/replay_pb").ReplayAllMessagesResult, import("/Users/fharvey/code/monolith/A-frontend/src/app/components/pages/RobotReporting/index").TypeSiloCollec...' is not assignable to parameter of type 'import("/Users/fharvey/code/monolith/web-common/node_modules/rxjs/internal/types").OperatorFunction<import("/Users/fharvey/code/monolith/web-common/services/scaffold/replay_pb").ReplayAllMessagesResult, import("/Users/fharvey/code/monolith/A-frontend/src/app/components/pages/RobotReporting/index").TypeSiloCollecti...'.
  Types of parameters 'source' and 'source' are incompatible.

简而言之,~"A-frontend/node_modules/rxjs/internal/types".OperatorFunction~"web-common/node_modules/rxjs/internal/types".OperatorFunction 不同。我已经看到很多这方面的:

这里有一个棘手的部分,那就是它在我的开发版本中有效,但不是我的产品版本。

通用 Webpack 配置

const path = require('path')
const webpack = require('webpack')
const CircularDependencyPlugin = require('circular-dependency-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const GitRevisionPlugin = require('git-revision-webpack-plugin')
const gitRevisionPlugin = new GitRevisionPlugin({
    /*
     * The gist of this command is
     * 1) Make -rc.X tags sort after main tags (so v3.0.2 is a higher version than v3.0.2-rc.3)
     * 2) Get all tags that point to the current commit, sort by version
     * 3) Return the first (i.e. most recent) tag name
     */
    versionCommand: 'config versionsort.suffix --add "-rc"; git tag --points-at HEAD --sort=-version:refname | head -n 1'
})
// Paths are relative to the client folder, not to this config file, as this is where node is run from

const commonConfig = {
    context: path.resolve('./src'),
    entry: {
        // 'sign-in': 'sign-in',
        // 'app': 'app',
        // home: 'home',                // Signed-out bundle
        'index': 'global'           // Signed-in bundle
    },
    module: {
        rules: [
            {
                test: /\.md$/, use: [
                    { loader: 'html-loader' },
                    { loader: 'markdown-loader' }
                ]
            },
            {
                test: /\.tsx?$/,
                loader: 'ts-loader'
            },
            {
                test: /\.less$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader',
                        options: { importLoaders: 1 }
                    },
                    { loader: 'postcss-loader' },
                    {
                        loader: 'less-loader',
                        options: {
                            javascriptEnabled: true
                        }
                    }
                ],
                // fallback: 'style-loader'
            },
            {
                test: /\.ttf$/,
                use: 'file-loader'
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.(svg|png)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192
                        }
                    }
                ]
            }
        ]
    },
    output: {
        publicPath: '/static/',
    },
    plugins: [
        new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // don't bundle unnecessary moment.js bloat
        new webpack.IgnorePlugin(/\.test\.tsx?/),
        new CircularDependencyPlugin({
            exclude: /a\.js|node_modules/,
            failOnError: true
        }),
        gitRevisionPlugin,
        new webpack.EnvironmentPlugin({
            VERSION: gitRevisionPlugin.version()
        })
    ],
    resolve: {
        extensions: ['.js', '.ts', '.tsx'],
        modules: [
            path.resolve('./src'),
            'node_modules'
        ],
        symlinks: false,    // linked dependency peer dependencies resolve correctly
        alias: {
            rxjs: path.resolve('./node_modules/rxjs'),
        },
    },
    optimization: {
        splitChunks: {
            // include all types of chunks
            chunks: 'all',
            cacheGroups: {
                react: {
                    test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
                    name: 'vendor-react',
                    chunks: 'all',
                },
                antd: {
                    test: /[\\/]node_modules[\\/](antd)[\\/]/,
                    name: 'vendor-antd',
                    chunks: 'all',
                }
            }
        }
    },
    target: 'web'
}

module.exports = commonConfig

开发 Webpack 配置

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

const commonConfig = require('./common.config')

const devConfig = Object.assign(commonConfig, {
    mode: 'development',
    devtool: 'eval-cheap-source-map',
    output: Object.assign(commonConfig.output, {
        filename: '[name].js', // [name] resolves to name of bundle (e.g., home, customer)
        chunkFilename: '[name].js',
        path: path.resolve('./build/static')
    }),
    stats: {
        warnings: false
    },
    module: {
        rules: [{
            test: /\.md$/,
            use: [{
                loader: 'html-loader'
            },
            {
                loader: 'markdown-loader'
            }
            ]
        },
        {
            test: /\.tsx?$/,
            use: [{
                loader: 'cache-loader'
            }, // caches typescript compilation,
            {
                loader: 'ts-loader',
                options: {
                    // disables type-checking so it can be handled by fork-ts-checker-webpack-plugin
                    transpileOnly: true
                }
            }
            ]
        },
        {
            test: /\.less$/,
            use: [
                MiniCssExtractPlugin.loader,
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 1
                    }
                },
                {
                    loader: 'postcss-loader'
                },
                {
                    loader: 'less-loader',
                    options: {
                        javascriptEnabled: true
                    }
                }
            ]
        },
        {
            test: /\.ttf$/,
            use: 'file-loader'
        },
        {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        },
        {
            test: /\.(svg|png)$/,
            use: [{
                loader: 'url-loader',
                options: {
                    limit: 8192
                }
            }]
        }
        ]
    },
    plugins: commonConfig.plugins.concat(
        new MiniCssExtractPlugin({
            filename: '[name].css'
        }),
        // Move typescript type checking to a separate process to speed up compile time
        new ForkTsCheckerWebpackPlugin({
            tsconfig: '../tsconfig.json',
            useTypescriptIncrementalApi: true, // uses incremental compilation api from typescript (2.7+)
            async: true // Used for docker
        }),
        new HtmlWebpackPlugin({
            filename: '../index.html',
            template: 'signed-in-template.html',
            favicon: 'assets/images/favicon.ico'
        }),
        new webpack.EnvironmentPlugin({
            //  some stuff 
        })
    )
})

module.exports = devConfig

产品 Webpack 配置

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const TerserJSPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");

const commonConfig = require('./common.config')

const prodConfig = Object.assign(commonConfig, {
    mode: 'production',
    devtool: false,
    output: Object.assign(commonConfig.output, {
        filename: '[name].[contenthash].js', // [name] resolves to name of bundle (e.g., home, customer)
        chunkFilename: '[name].[contenthash].js',
        path: path.resolve('./prod/static')
    }),
    plugins: commonConfig.plugins.concat(
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css'
        }),
        new ForkTsCheckerWebpackPlugin({
            tsconfig: '../tsconfig.json',
            useTypescriptIncrementalApi: true, // uses incremental compilation api from typescript (2.7+)
            async: true // Makes docker work
        }),
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': JSON.stringify('production')
            }
        }),
        new HtmlWebpackPlugin({
            filename: '../index.html',
            template: 'signed-in-template.html',
            favicon: 'assets/images/favicon.ico'
        }),
        new webpack.EnvironmentPlugin({
            // some stuff
        })
    ),
    optimization: Object.assign(commonConfig.optimization, {
        minimizer: [
            new TerserJSPlugin({
                parallel: true
            }),
            new OptimizeCSSAssetsPlugin({})
        ]
    })
})

module.exports = prodConfig

tsconfig

{
    "compilerOptions": {
        "skipLibCheck": true,
        "alwaysStrict": true,
        "baseUrl": "src",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "forceConsistentCasingInFileNames": true,
        "jsx": "react",
        "module": "esnext",
        "moduleResolution": "node",
        "lib": [
            "dom",
            "es2015" // Promise, classes, etc. tsc injects shims for ES5 browsers
        ],
        "noImplicitAny": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "strictNullChecks": true,
        "target": "es5",
        "types": [
            "reflect-metadata",
            "googlemaps",
            "google.analytics",
            "jest",
            "jest-enzyme"
        ],
        "paths": {
            "*": [
                "node_modules/@types/*",
                "*"
            ],
            "rxjs": [
                "node_modules/rxjs"
            ],
            "rxjs/*": [
                "node_modules/rxjs/*"
            ]
        },
    },
    "exclude": [
        "node_modules",
        "src/**/*.test.ts",
        "src/**/*.test.tsx",
        "node_modules/web-common/node_modules/*"
    ],
    "include": [
        "src/**/*.ts",
        "src/**/*.tsx",
        "typings/*.d.ts"
    ]
}

我很抱歉没有减少我的粘贴,此时我真的不知道为什么会发生这种情况,并认为我会包括所有内容。我使用任何import ... from "rxjs/internal",但这是在幕后发生的。对于任何其他依赖项,这不会发生,也从未发生过。我尝试安装web-common 而不是链接,没有骰子。

【问题讨论】:

    标签: typescript npm webpack rxjs


    【解决方案1】:

    我认为这对于您的开发构建也是一个错误,但它不会因 TS 错误而失败,因为您在开发 ts-loader 配置中设置了 transpileOnly: true

    这些类型总是不兼容的,因为它们来自 2 个不同的 RxJS 安装——作为 2 个不同的模块。我能想到的唯一直接解决此问题的方法是将 web-common 物理安装到您的项目中,至少在进行生产构建之前。


    这只是一个 Typescript 错误,只要 2 个 RxJS 安装是兼容的版本,实际构建的 JS 代码可能运行得很好。

    然而,webpack 可能会以同样的方式考虑这一点, 可能会在包中添加 2 个版本的 RxJS——web-common 使用的 1 个版本和 A-frontend 使用的另一个版本。 p>

    【讨论】:

      猜你喜欢
      • 2022-01-22
      • 2019-09-06
      • 2021-10-09
      • 2020-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      相关资源
      最近更新 更多