到底要怎样才能在 vue3 的 vue 文件里使用上完整的 TS 语法? 只能用一半可太离谱了

2021-03-27 21:10:12 +08:00
 skypyb

某一部分特性在 vue 文件里还能用上一点,比如类型约束,IDE 做类型推断也还行。

但是会有些其他的特性用不了, 比如我遇到这这俩问题。
一个是接口不能直接在 type='ts' 的 script 块中定义。(试了下类也一样)
还有就是无法使用类型断言。

在 .ts 文件里就能用, 在 vue 里就不能用。 你说像是接口这种就算了, 定义在 ts 文件里引进来我还能拿着用 (?其实这也很怪)。 像这种需要做类型断言的地方我就真的是没办法了...

Unexpected reserved word 'interface' (6:4)

  4 |     import {NotesView} from '@/api/uinfo-service';
  5 |
> 6 |     interface Ass {
    |     ^
  7 |         asv: string
  8 |     }
  9 |

 Unexpected token, expected "," (10:29)

   8 |         props: {
   9 |             note: {
> 10 |                 type: Object as PropType<NotesView>,
     |                              ^
  11 |                 required: true
  12 |             }
  13 |         },


搜遍了各个地方, 没找到相似的例子。我甚至不知道是什么地方出的问题。 版本?插件?配置?
没办法只能来这求助啦


下边贴几个文件, 大佬们帮看下呗😭


package.json

{
  "name": "fev-test",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "@ant-design/icons-vue": "^6.0.1",
    "ant-design-vue": "^2.0.0",
    "axios": "^0.21.1",
    "babel-plugin-import": "^1.13.3",
    "compression-webpack-plugin": "^7.1.2",
    "core-js": "^3.8.3",
    "script-ext-html-webpack-plugin": "^2.1.5",
    "vue": "^3.0.5",
    "vue-class-component": "^8.0.0-rc.1",
    "vue-loader": "^15.9.6",
    "vue-loader-v16": "^16.0.0-beta.5.4",
    "vue-router": "^4.0.3",
    "vuex": "^4.0.0"
  },
  "devDependencies": {
    "@types/chai": "^4.2.11",
    "@types/lodash": "^4.14.161",
    "@types/mocha": "^5.2.4",
    "@typescript-eslint/eslint-plugin": "^4.15.0",
    "@typescript-eslint/parser": "^4.15.0",
    "@vue/cli-plugin-babel": "~4.5.11",
    "@vue/cli-plugin-eslint": "~4.5.11",
    "@vue/cli-plugin-router": "~4.5.11",
    "@vue/cli-plugin-typescript": "~4.5.11",
    "@vue/cli-plugin-vuex": "~4.5.11",
    "@vue/cli-service": "~4.5.11",
    "@vue/compiler-sfc": "^3.0.5",
    "@vue/eslint-config-prettier": "^6.0.0",
    "@vue/eslint-config-typescript": "^7.0.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^7.20.0",
    "eslint-plugin-html": "^6.1.1",
    "eslint-plugin-prettier": "^3.3.1",
    "eslint-plugin-vue": "^7.6.0",
    "less": "^4.1.1",
    "less-loader": "^7.3.0",
    "prettier": "^2.2.1",
    "style-resources-loader": "^1.4.1",
    "typescript": "~4.1.5",
    "vue-cli-plugin-style-resources-loader": "~0.1.4",
    "webpack-bundle-analyzer": "^4.4.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "declaration": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "skipLibCheck": false,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "suppressImplicitAnyIndexErrors": true,
    "sourceMap": false,
    "baseUrl": ".",
    "rootDir": ".",
    "types": [
      "webpack-env",
      "chai",
      "mocha"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "exclude": [
    "node_modules",
    "dist"
  ]
}

babel.config.js

module.exports = {
  presets: ['@vue/cli-plugin-babel/preset']
};

.eslintrc.js

module.exports = {
    root: true,
    parserOptions: {
        parser: '@typescript-eslint/parser',
    },
    env: {
        browser: true,
        es6: true,
        node: true,
    },
    plugins: ['vue', '@typescript-eslint/eslint-plugin'],
    rules: {
        'no-unused-vars': 'off',
        '@typescript-eslint/no-explicit-any': 'off',
        '@typescript-eslint/member-delimiter-style': 'off',
        '@typescript-eslint/ban-ts-ignore': 'off',
        '@typescript-eslint/class-name-casing': 'off',
        'vue/valid-v-slot': 'off',
        'vue/experimental-script-setup-vars': 'off',

        'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',

        indent: ['off', 4, {SwitchCase: 1}], // 缩进不管

        'line-comment-position': [
            'off',
            {position: 'above', ignorePattern: 'ETC'},
        ], // 强制行注释的位置
        'vue/no-v-model-argument': 'off',
        'vue/no-setup-props-destructure': 'off',
        'vue/no-multiple-template-root': 'off',
        '@typescript-eslint/no-var-requires': 0,
        'vue/html-indent': ['warn', 4],

        quotes: ['error', 'single'], // 使用单引号
    },
    extends: [
        'plugin:vue/vue3-essential',
        'eslint:recommended',
        '@vue/typescript/recommended',
    ],
    overrides: [
        {
            files: [
                '**/tests/*.{j,t}s?(x)',
                '**/tests/**/*.spec.{j,t}s?(x)',
                '**/tests/*.spec.{j,t}s?(x)',
            ],
            env: {
                mocha: true,
            },
        },
    ],
};

vue.config.js

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
    .BundleAnalyzerPlugin

const IS_DEV = process.env.NODE_ENV !== 'production'
/**
 * @todo 开发环境配置
 * 某些实用工具,plugins 和 loaders 都只能在构建生产环境时才有用
 * 在开发时使用 UglifyJsPlugin 来压缩和修改代码是没有意义的,不压缩
 */

const DEVELOPMENT = webpackConfig => {
    /**
     * @todo 启用 eval-source-map 更好的测试
     * 每个模块使用 eval() 执行,并且 source map 转换为 DataUrl 后添加到 eval() 中。
     * 初始化 source map 时比较慢,但是会在重新构建时提供比较快的速度,并且生成实际的文件。
     * 行数能够正确映射,因为会映射到原始代码中。它会生成用于开发环境的最佳品质的 source map 。
     */

    webpackConfig.store.set('devtool', 'eval-source-map')
    webpackConfig.plugin('html').tap(([options]) => [
        Object.assign(options, {
            minify: false,
            chunksSortMode: 'none'
        })
    ])

    // webpackConfig.plugin('BundleAnalyzerPlugin').use(BundleAnalyzerPlugin)

    return webpackConfig
}

/**
 * @todo 生产环境配置
 * 每个额外的 loader/plugin 都有启动时间。尽量少使用不同的工具
 */

const PRODUCTION = webpackConfig => {
    /**
     * @todo 不需要启用 source-map,去除 console 的情况下 source-map 根本没用,还浪费大量时间和空间
     * 详情见: https://webpack.js.org/configuration/devtool/#devtool
     */
    webpackConfig.store.set('devtool', '')
    webpackConfig.plugin('html').tap(([options]) => [
        Object.assign(options, {
            minify: {
                removeComments: true,
                removeCommentsFromCDATA: true,
                collapseWhitespace: true,
                conservativeCollapse: false,
                collapseInlineTagWhitespace: true,
                collapseBooleanAttributes: true,
                removeRedundantAttributes: true,
                removeAttributeQuotes: false,
                removeEmptyAttributes: true,
                removeScriptTypeAttributes: true,
                removeStyleLinkTypeAttributes: true,
                useShortDoctype: true,
                minifyJS: true,
                minifyCSS: true
            },
            cache: true, // 仅在文件被更改时发出文件
            hash: true, // true 则将唯一的 webpack 编译哈希值附加到所有包含的脚本和 CSS 文件中,这对于清除缓存很有用
            scriptLoading: 'defer', // 现代浏览器支持非阻塞 javascript 加载('defer'),以提高页面启动性能。
            inject: true, // true 所有 javascript 资源都将放置在 body 元素的底部
            chunksSortMode: 'none'
        })
    ])

    return webpackConfig
}

module.exports = {
    publicPath: '/',
    css: {
        loaderOptions: {
            less: {
                sourceMap: IS_DEV,
                lessOptions: {
                    javascriptEnabled: true
                }
            }
        }
    },
    devServer: {
        proxy: 'http://10.10.10.115:8002'
    },
    pluginOptions: {
        /** 全局加载 less 的 webpack 插件  */
        'style-resources-loader': {
            preProcessor: 'less',
            patterns: ['./src/styles/index.less']
        }
    },
    /**
     * @description 去掉 console 信息
     *  config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true;
     *  html-webpack-plugin 插件配置详情见 https://github.com/jantimon/html-webpack-plugin#options
     */
    configureWebpack: config => {
        config.optimization = {
            splitChunks: {
                chunks: 'all',
                minSize: 3000, // (默认值:30000 )块的最小大小。
                minChunks: 1, //(默认值:1 )在拆分之前共享模块的最小块数
                maxAsyncRequests: 5, //(默认值为 5 )按需加载时并行请求的最大数量
                maxInitialRequests: 6, // (默认值为 3 )入口点的最大并行请求数
                automaticNameDelimiter: '-',
                name: true,
                cacheGroups: {
                    lodash: {
                        name: 'lodash',
                        test: /[\\/]node_modules[\\/]lodash[\\/]/,
                        priority: 20
                    },
                    vue: {
                        name: 'vue',
                        test: /[\\/]node_modules[\\/]vue[\\/]/
                    },
                    vuex: {
                        name: 'vuex',
                        test: /[\\/]node_modules[\\/]vuex[\\/]/
                    },
                    'vuex-presistedstate': {
                        name: 'vuex-presistedstate',
                        test: /[\\/]node_modules[\\/]vuex-presistedstate[\\/]/
                    },
                    'vue-router': {
                        name: 'vue-router',
                        test: /[\\/]node_modules[\\/]vue-router[\\/]/
                    },
                    'ant-design-vue': {
                        name: 'ant-design-vue',
                        test: /[\\/]node_modules[\\/]ant-design-vue[\\/]/
                    },
                    moment: {
                        name: 'moment',
                        test: /[\\/]node_modules[\\/]moment[\\/]/,
                        priority: 40
                    }
                }
            }
        }
    },
    chainWebpack: config => {
        config.resolve.symlinks(true)

        if (process.env.use_analyzer) {
            config.plugin('webpack-bundle-analyzer').use(BundleAnalyzerPlugin)
        }

        IS_DEV ? DEVELOPMENT(config) : PRODUCTION(config)
    },
    productionSourceMap: false,
    lintOnSave: true
}

6318 次点击
所在节点    Vue.js
24 条回复
Jaosn
2021-03-29 00:07:22 +08:00
这个帖子给我看乐了,几个回复也十分有趣,比如我楼上这位
Sparetire
2021-03-29 02:54:13 +08:00
建议 Vue3 用 volar, Vue2 用 vetur
rodrick
2021-03-29 11:43:03 +08:00
不明白 vue 写 ts 怎么就有人觉得能上升到脑子不好了
xiaoliaoliao
2021-03-29 16:26:32 +08:00
推荐 volar 但是这插件也不是很成熟 eslint 没法用,如果需要未使用变量报错可以在 tsconfig 的 compilerOptions 中增加字段"noUnusedLocals": true

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/765761

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX