迁移准备
动态类型一时爽 代码重构火葬场
TypeScript其与JavaScript的区别是提供的静态类型系统,一些错误可以再编译阶段尽早的发现和解决,提高了代码的健壮性,增强了代码的可读性以及可维护性,动态类型一时爽 代码重构火葬场
之前很流行的一句话也可以很好的解释他们的区别,也正式这个原因开始把既有项目迁移到TypeScript 语言上来。
以上是一些基本教程,如果你已经熟悉TypeScript 和webpack 的基本知识,可以跳过上面,开始迁移
添加 TypeScript 配置文件 tsconfig.json
tsconfig.json 文件中指定了用来编译这个项目的根文件和编译选项。 首先在项目中安装 typescript npm install typescript
or yarn add typescript
。 然后在项目的根目录下添加 TypeScript 配置文件 tsconfig.json 文件, 使用npx tsc --init
可以配置。
{
"compilerOptions": {
"outDir": "/dist",
"module": "esnext",
"target": "es6",
"lib": ["es6", "dom"],
"sourceMap": true,
"baseUrl": ".",
"jsx": "react",
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"rootDirs": ["/src", "/test", "/mock","./typings"],
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"allowJs": true,
"experimentalDecorators": true,
"paths": {
"@/*": ["./src/*"]
},
},
"include": ["./src"],
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts",
"tslint:latest",
"tslint-config-prettier"
]
}
复制代码
- 读取所有可识别的 src 目录下的文件(通过 include)。
- 接受 JavaScript 做为输入(通过 allowJs)。
- 使用react ,"jsx"设置为"react",
- 生成的所有文件放在 built 目录下(通过 outDir)。
- 将 JavaScript 代码降级到低版本比如 ECMAScript 5(通过 target)'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'。
- "module": "esnext", 指定模块的方式,可以为'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'.
webpack 的配置
webpack.config.js 中需要加上 ts 的 loader 规则,ts 的rule 规则要在js 的rule 之前 ,以及添加配置解析的文件格式。下面就是 ts 配置在最前面且 tsconfig 转成 es2016 的形式,如何确保编译之后的代码再被 babel loader 编译成 es5 的形式? rules 规则数组到条件把以.tsx
文件应用ts-loader 处理,并且 ts-loader 用于处理 ts 和 tsx 文件,解决这个问题需要以下两个步骤
- 使用 ts-loader 把 ts 代码编译到 ES6
- 使用 babel 把 ES6 代码 和 jsx 编译到 ES5
webpack 的配置通常如下
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
},
{
loader: 'ts-loader'
}
]
}
// . babelrc 文件配置
{
"presets": [
"@babel/env",
"@babel/preset-typescript"
],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread"
]
}
复制代码
配置扩展
下一代的 babel 7 带来了新的能力,有了解析 typescript 的能力,让我们可以不需要在编译两轮了。 babeljs.io/docs/en/bab…) .babelrc 配置如下:
{
"presets": [
"@babel/env",
"@babel/react",
"@babel/typescript"
]
}
复制代码
以下通过几种方式,来查看bulid打包后的文件中是否含有箭头函数的=>,const等。
第1种配置
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'babel-loader'
},
// . babelrc 文件配置以及对应的babel 要升级到版本7.4.0以上
{
"presets": [
"@babel/env",
"@babel/preset-typescript"
],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread"
]
}
复制代码
第2种配置
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader'
},
复制代码
第3种配置
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: 'babel-loader',
},
{
loader: 'ts-loader'
}
]
},
复制代码
以上方式的配置中,在build 打包后的文件中都有=>,const 等的原因是tsconfig.json文件配置为"target": "es2016",的方式, 然后把tsconfig.json文件配置为"target": "es5",以上3种方式打包后的文件中都没有=> ,const等。
- ts-loader 可以根据tsconfig.json的一个基本的配置,来支持 JSX,并将 TypeScript 编译到target指定的形式,如 ES5,es2016等
- 以上都是分别针对ts文件和js文件分开处理
经过以上实验和考虑到webpack 的tree sharking优化, 我们的项目采用第三种方式。
找不到对应模块 Cannot find module './style.css
这个要看是第三方插件还是自己的模块,如果是第三方插件,使用npm 进行安装,如果是自己写的业务模块,就是引用路径的问题,这个要和tsconfig 文件的配置相对应。
为什么切 ts 会影响代码的写法,能否统一成 import 写法?
因为一直出现 Cannot find module './style.css'.
这个问题,找了官方的解释如下:
Using CSS Modules with TypeScript is not as obvious as with JavaScript. The reason is that TypeScript has special treatment for imports and if you try to use CSS Modules the same way you did in JavaScript:
有两种解决方案如下:
- 最简单的方式使用require的方式
const style = require("./style.css");
- 使用 typings-for-css-modules-loader
- npm install --save-dev typings-for-css-modules-loader
- 修改wepack 配置
//...
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'typings-for-css-modules-loader',
options: {
modules: true,
namedExport: true
}
}
]
}
]
复制代码
添加以上配置才可以使用 import 的方式。import style from './style.css';
转换为 .tsx 文件相应改变
- react 组件的更改
- 组件传入类型的定义
- 函数类型的声明定义
- props 和 state 都要做类型限制
import React from 'react';
import { connect } from 'react-redux';
import { getAuth } from '../../../modules/app/reducers/user/auth';
// import style from './style.css';
const style = require("./style.css");
interface propTypes{
getAuth: ()=>void;
}
class LoginScene extends React.PureComponent<propTypes> {
handleClick = () => {
this.props.getAuth();
};
render() {
return (
<div className={style.login}>
// ...
</div>
);
}
}
复制代码