前言

本篇文章默认您大概了解什么是TypeScript,主要讲解如何在React旧项目中安装并使用TypeScript。

写这个的目的主要是网上关于TypeScript这块的讲解虽然很多,但都是一些语法概念或者简单例子,真正改造一个React旧项目使用TypeScript的文章很少。

所以在这里记录下改造一个React项目的实践。

博客内容部分参照 TypeScript中文网,这个网站有官方文档的中文版。

安装TypeScript及相关库

对于集成了TypeScript的脚手架可以略过这一步,这里主要讲一下如何将TypeScript集成到一个React脚手架中。

首先执行

  1. npm install --save @types/react @types/react-dom

这一步主要是为了获取react和react-dom的声明文件,因为并不是所有的库都有TypeScript的声明文件,所以通过运行

  1. npm install --save @types/库名字

的方式来获取TypeScript的声明文件。

只有获取了声明文件,才能实现对这个库的类型检查。

如果你使用了一些其它的没有声明文件的库,那么可能也需要这么做。

然后运行命令:

  1. npm install --save-dev typescript awesome-typescript-loader source-map-loader

这一步,我们安装了typescript、awesome-typescript-loader和source-map-loader。

awesome-typescript-loader可以让Webpack使用TypeScript的标准配置文件tsconfig.json编译TypeScript代码。

source-map-loader使用TypeScript输出的sourcemap文件来告诉webpack何时生成自己的sourcemaps,源码映射,方便调试。

添加TypeScript配置文件

在项目根目录下创建一个tsconfig.json文件,以下为内容示例:

  1. {
  2. "compilerOptions": {
  3. "allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查。
  4. "outDir": "./dist/", // 重定向输出目录
  5. "sourceMap": true, // 生成相应的 .map文件
  6. "noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错。(默认为false,个人建议也为false,可以兼容之前的js代码,这里改为true是为了我自己检测哪些类型需要处理)
  7. "module": "esnext", // 模块引入方式
  8. "target": "es6", // 指定ECMAScript目标版本
  9. "moduleResolution": "node", // 决定如何处理模块
  10. "lib": [
  11. "esnext",
  12. "dom"
  13. ], // 编译过程中需要引入的库文件的列表。
  14. "skipLibCheck": true, //忽略所有库中的声明文件( *.d.ts)的类型检查。
  15. "jsx": "react" // 在 .tsx文件里支持JSX
  16. },
  17. "include": [
  18. "./src/**/*", // 这个表示处理根目录的src目录下所有的.ts和.tsx文件,并不是所有文件
  19. ]
  20. }

skipLibCheck非常重要,并不是每个库都能通过typescript的检测。

moduleResolution设为node也很重要。如果不这么设置的话,找声明文件的时候typescript不会在node_modules这个文件夹中去找。

更多配置文件信息可以参考:这里

配置webpack

这里列出一些TypeScript需要在webpack中使用的配置。

解析tsx文件的rule配置

示例如下:

  1. module: {
  2. rules: [
  3. {
  4. test: /\.jsx?$/,
  5. exclude: /(node_modules)/,
  6. use: {
  7. loader: 'babel-loader',
  8. options: {
  9. presets: ['react', 'env', 'stage-0', 'stage-3'],
  10. plugins: [
  11. 'transform-decorators-legacy',
  12. ['import', { libraryName: 'antd', style: 'css' }], // `style: true` 会加载 less 文件
  13. ],
  14. },
  15. },
  16. },
  17. { test: /\.tsx?$/, loader: "awesome-typescript-loader" }
  18. //...
  19. ]
  20. //...
  21. }

其实就只是多加了一行:

  1. { test: /\.tsx?$/, loader: "awesome-typescript-loader" }

注意这一行需要加在解析jsx的rule下面,因为rule的执行顺序是从下往上的,先解析tsx和ts再解析js和jsx。

当然用

  1. enforce: 'pre'

调整过rule顺序的可以不用在意这一点。

解决使用css-moudule的问题

如果代码中使用了以下这种代码:

  1. import styles from './index.css'

那么很可能报下面的错:

  1. Cannot find module './index.css'

解决方法就是在根目录下新建文件一个叫declaration.d.ts的文件,内容为:

  1. declare module '*.css' {
  2. const content: any;
  3. export default content;
  4. }

这行代码就是为所有的css文件进行声明。

同时需要更改一下我们之前的tsconfig.json文件,将这个文件路径放在include中:

  1. "include": [
  2. "./src/**/*",
  3. "./declaration.d.ts"
  4. ]

这个问题有通过安装一些库来解决的办法,但是会给每个css生成一个声明文件,感觉有点奇怪,我这里自己考虑了一下采用了上面这种方法。

用于省略后缀名的配置

如果你惯于在使用

  1. import Chart from './Chart/index.jsx'

时省略后缀,即:

  1. import Chart from './Chart/index'

那么在webpack的resolve中同样需要加入ts和tsx:

  1. resolve: {
  2. extensions: [".ts", ".tsx", ".js", ".jsx"]
  3. },

引入Ant Design

实际上这个东西Ant Design的官网上就有怎么在TypeScript中使用:在 TypeScript 中使用

那么为什么还是要列出来呢?

因为这里要指出,对于已经安装了Ant Design的旧项目而言(一般都是配了按需加载的吧),在安装配置TypeScript时上面这个文档基本没有任何用处。

在网上可以搜到的貌似都是文档中的方案,而实际上我们需要做的只是安装ts-import-plugin

  1. npm i ts-import-plugin --save-dev

然后结合之前的 awesome-typescript-loader ,在webpack中进行如下配置

  1. const tsImportPluginFactory = require('ts-import-plugin')
  2. module.exports = {
  3. // ...
  4. module: {
  5. rules: [
  6. {
  7. test: /\.tsx?$/,
  8. loader: "awesome-typescript-loader",
  9. options: {
  10. getCustomTransformers: () => ({
  11. before: [tsImportPluginFactory([
  12. {
  13. libraryName: 'antd',
  14. libraryDirectory: 'lib',
  15. style: 'css'
  16. }
  17. ])]
  18. }),
  19. },
  20. exclude: /node_modules/
  21. }
  22. ]
  23. },
  24. // ...
  25. }

配置完成,修改前的准备

注意,直到这一步,实际上您的项目在编译过程中仍然没有用到TypeScript。

因为我们这里只会用TypeScript处理.ts和.tsx后缀的文件,除非在配置中将allowJs设为true。

在使用之前,默认您已经对TypeScript语法有了了解,不了解可以参考:5分钟上手TypeScript

也就是说,经过了上面的这些步骤,您的原有代码在不改动后缀的情况下应该是可以继续用的。

如果要使用TypeScript,那么新建tsx和ts文件,或者修改原有的文件后缀名即可。

接下来会列出一些典型的修改示例。

函数式组件的修改示例(含children)

  1. import React from 'react'
  2. import styles from './index.css'
  3. interface ComputeItemProps {
  4. label: string;
  5. children: React.ReactNode;
  6. }
  7. function ComputeItem({ label, children }: ComputeItemProps) {
  8. return <div className={styles['item']}>
  9. <div className={styles['label']}>{label}:</div>
  10. <div className={styles['content']}>{children}</div>
  11. </div>
  12. }
  13. export default ComputeItem
  14. 这个例子中语法都可以在TypeScript的官网查到,唯一需要注意的是children的类型是React.ReactNode

class组件修改示例(含函数声明,事件参数的定义)

  1. import React from 'react'
  2. import styles from './index.css'
  3. interface DataSourceItem {
  4. dayOfGrowth: string;
  5. netValueDate: string;
  6. }
  7. interface ComputeProps {
  8. fundCode: string;
  9. dataSource: DataSourceItem[];
  10. onChange(value: Object): void;
  11. }
  12. export default class Compute extends React.Component<ComputeProps, Object> {
  13. // 改变基金代码
  14. handleChangeFundCode = (e: React.ChangeEvent<HTMLInputElement>) => {
  15. const fundCode = e.target.value
  16. this.props.onChange({
  17. fundCode
  18. })
  19. }
  20. render() {
  21. //...
  22. );
  23. }
  24. }

这个例子展示如何声明class组件:

  1. React.Component<ComputeProps, Object>

语法虽然看起来很怪,但是这就是TypeScript中的泛型,以前有过C#或者Java经验的应该很好理解。

其中,第一个参数定义Props的类型,第二个参数定义State的类型。

而react的事件参数类型应该如下定义:

  1. React.ChangeEvent<HTMLInputElement>

这里同样使用了泛型,上面表示Input的Change事件类型。

而组件的Prop上有函数类型的定义,这里就不单独列出来了。

这几个例子算是比较典型的TypeScript与React结合的例子。

处理window上的变量

使用写在window上的全局变量会提示window上不存在这个属性。

为了处理这点,可以在declaration.d.ts这个文件中定义变量:

  1. // 定义window变量
  2. interface Window{
  3. r:string[]
  4. }

其中r是变量名。

处理别名问题(2019年12月2日更新)

如果你的代码在webpack中定义了别名,即:

  1. resolve: {
  2. alias: {
  3. common: path.resolve(__dirname, 'src/common'),
  4. modules: path.resolve(__dirname, 'src/modules'),
  5. store: path.resolve(__dirname, 'src/store'),
  6. }
  7. },

那么使用这种别名的时候:

  1. import { PageReduxState } from 'store/reducers';

typescript会找不到相应模块。

为了解决这个问题,需要在tsconfig.json中配置解析路径:

  1. {
  2. "compilerOptions": {
  3. // ...
  4. // ts下别名的检测
  5. "baseUrl": "./src",
  6. "paths": {
  7. "common/*": ["common/*"],
  8. "modules/*": ["modules/*"],
  9. "store/*": ["store/*"]
  10. }
  11. },
  12. //...
  13. }

typescript解析扩展运算符报错(2019年12月13日更新)

报错提示如下:

  1. ERROR in ./src/modules/pageMain/index.tsx 40:16
  2. Module parse failed: Unexpected token (40:16)
  3. You may need an appropriate loader to handle this file type.
  4. | this.handleChange = (params) => {
  5. | this.setState({
  6. > ...this.state,
  7. | ...params
  8. | }, this.getList);
  9. @ ./src/route/index.js 28:9-35
  10. @ ./src/app.js
  11. @ multi babel-polyfill ./src/app.js

解决方案:

尝试将tsconfig.json中

  1. "target": "esnext"

修改为

  1. "target": "es6"

即可。

总结

本来还想再多写几个示例的,但是Dota2版本更新了,导致我不想继续写下去了,以后如果有时间再更新常用的示例吧。

本篇文章只专注于在React旧项目中安装并集成TypeScript,尽可能做到不涉及TypeScript的具体语法与介绍,因为介绍这些东西就不是一篇博客能搞定的了。

文章如有疏漏还请指正,希望能帮助到在TypeScript面前迟疑的你。

在React旧项目中安装并使用TypeScript的实践的更多相关文章

  1. Immutable.js 以及在 react+redux 项目中的实践

    来自一位美团大牛的分享,相信可以帮助到你. 原文链接:https://juejin.im/post/5948985ea0bb9f006bed7472?utm_source=tuicool&ut ...

  2. webpack学习(一)项目中安装webpack

    如何在项目中安装webpack,webpack-cli? 前提:电脑安装了 node和npm包管理工具 1 创建项目文件夹或者在已有的项目中打开终端  输入相关命令: npm init 因为已经安装好 ...

  3. SuperDiamond在JAVA项目中的三种应用方法实践总结

    SuperDiamond在JAVA项目中的三种应用方法实践总结 1.直接读取如下: @Test public static void test_simple(){ PropertiesConfigur ...

  4. ios项目中安装和使用CocoaPods

    CocoaPods是什么? http://code4app.com/article/cocoapods-install-usage http://blog.csdn.net/jjmm2009/arti ...

  5. iOS项目中安装和使用 Cocoapods

    1.首先我们要打开我们的终端: 2.在终端输入 这条命令  gem sources -l 2.1如果是和我是一样的显示,则镜像已添加,无需更改,如果不一样,则需要进行更改 这里输出的如果是 https ...

  6. 在vue项目中安装使用Mint-UI

    一.Mint UI 是 由饿了么前端团队推出的 一个基于 Vue.js 的移动端组件库,具有以下特性:       使用文档: http://mint-ui.github.io/#!/zh-cn Mi ...

  7. CocoaPods -- ios项目中安装和使用CocoaPods

    CocoaPods是什么? 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而 ...

  8. vue踩坑记-在项目中安装依赖模块npm install报错

    在维护别人的项目的时候,在项目文件夹中安装npm install模块的时候,报错如下: npm ERR! path D:\ShopApp\node_modules\fsevents\node_modu ...

  9. vue 项目中安装npm--save-dev 和 --save 命令

    在vue项目中我们常用npm install 安装模块或插件 有两种命令把他们写入到 package.json 文件里面去 例如安装axios 安装到开发环境npm axios --save-dev ...

随机推荐

  1. 百万年薪python之路 -- 递归

    递归(每当有一个函数被递归调用,就应该要有一个返回值,才能正常把递归的返回值'归'回来) 一个正经的递归: ​ 1.不断调用自己本身 ​ 2.有明确的结束条件 递归注重于"一递 一归&quo ...

  2. Linux 修改网卡名

    1. 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens32 (“ens32”为当前网卡名) 将NAME.DEVICE项修改为eth0 2.  ...

  3. django-Views之常见的几种错误视图代码(三)

    1.404 page not found(找不到对应的页面) 2.500 server error(服务器错误) 3.400 bad request(无效的请求) 4.403 HTTP forbidd ...

  4. spring cloud 2.x版本 Ribbon服务发现教程(内含集成Hystrix熔断机制)

    本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 前言 本文基于前两篇文章eureka-server和eureka-client的实现. 参考 ...

  5. 在移动硬盘中安装win10和macos双系统

    本文通过在SSD移动硬盘中安装win10和macos双系统,实现操作系统随身携带 小慢哥的原创文章,欢迎转载 目录 ▪ 目标 ▪ 准备工作 ▪ Step1. 清空分区,转换为GPT ▪ Step2. ...

  6. 五、docker-compose开锋(docker 三剑客)

    前言 终于写到docker-compose了,其实我最开始接触docker的时候,是因为一个开源项目需要用docker 环境和docke-compose 所以我最先接触的是docker-compse ...

  7. SROP的一个实例

    以前一直只是大概看过这种技术,没实践过,今天刚好遇到一道题,实践了一波,确实很方便 unmoxiao@cat ~/s/pd_ubuntu> r2 -A smallest 00:54:15 War ...

  8. javascript 作用域链及性能优化

    在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象.函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性.其中一个内部属 ...

  9. 使用Typescript重构axios(十六)——请求和响应数据配置化

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  10. P2380 狗哥采矿

    #include<iostream> #include<algorithm> #include<cstring> ; using namespace std; in ...