中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

React項目怎么從Javascript到Typescript

發布時間:2021-09-13 16:55:08 來源:億速云 閱讀:276 作者:chen 欄目:web開發

本篇內容介紹了“React項目怎么從Javascript到Typescript”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

開始遷移

在開始遷移之前,我要說點題外話,本篇文章僅是記錄我在遷移過程中遇到的問題以及我是如何解決的,并不會涉及typescript的教學。所以大家在閱讀本篇文章之前,一定要對typescript有一個基礎的認識,不然你讀起來會非常費力。

環境調整

由于Typescript是Javascript的超集,它的很多語法瀏覽器是不能識別的,因此它不能直接運行在瀏覽器上,需要將其編譯成JavaScript才能運行在瀏覽器上,這點跟ES6需要經過babel編譯才能支持更多低版本的瀏覽器是一個道理。

tsconfig.json

首先我們得裝一個typescript,這就跟我們在用babel前需要先裝一個babel-core是一個道理。

yarn global add typescript

這條命令是將typescript安裝在全局,其實我個人建議是裝在項目目錄下的,因為每個項目的typescript版本是不完全一樣的,裝在全局容易因為版本不同而出現問題。但是后面我要執行tsc命令,所以我裝在了全局。***的情況就是全局和項目都裝一個,但是如果你把tsc命令放在package.json中的script中去用的話,那么在項目里裝就夠了。接下來我們執行如下命令生成tsconfig.json,這玩意就跟.babelrc是一個性質的。

tsc --init

執行完之后,你的項目根目錄下便會有一個tsconfig.json這么一個東西,但是里面會有很多注釋,我們先不用管他的。

webpack

安裝ts-loader用于處理ts和tsx文件,類似于babel-loader。

yarn add ts-loader -D

相應的webpack需要加上ts的loader規則:

module.exports = {      //省略部分代碼...      module: {          rules: [              {                  test:/\.tsx?$/,                  loader:'ts-loader'              }              //省略部分代碼...          ]      }      //...省略部分代碼  }

之前用javascript的時候,可能有人不使用.jsx文件,整個項目都是用的.js文件,webapck里面甚至都不配.jsx的規則。但是在typescript項目中想要全部使用.ts文件這就行不通了,會報錯,所以當用到了jsx的用法的時候,還是得乖乖用.tsx文件,因此這里我加入了.tsx的規則。

刪除babel

關于babel這塊,網上有不少人是選擇留著的,理由很簡單,說是為了防止以后會使用到JavaScript,但是我個人覺得是沒有必要留著babel。因為我們整個項目里面基本上只有使用第三方包的時候才會用到javascript,而這些第三方包基本上都是已經編譯成了es5的代碼了,不需要babel再去處理一下。而業務邏輯里面用javascript更是不太可能了,因為這便失去了使用typescript的意義。綜上所述,我個人覺得是要刪除babel相關的東西,降低項目復雜度。但是有一個例外情況:。

當你用了某些babel插件,而這些插件的功能恰巧是typescript無法提供的,那你可以保留babel,并且與typescript結合。

文件名調整

整個src目下所有的.js結尾的文件都要修改文件名,使用到jsx語法的就改成.tsx文件,未使用的就改成.ts文件,這塊工作量比較大,會比較頭疼。另外改完之后文件肯定會有很多標紅的地方,不要急著去改它,后面我們分類統一去改。

解決報錯

webpack入口文件找不到

React項目怎么從Javascript到Typescript

由于我們在做文件名調整的時候,把main.js改成main.tsx,因此webpack的入口文件要改成main.tsx。

module.exports = {      //省略部分代碼...      entry: {          app: './src/main.tsx'      },      //省略部分代碼...  }

提示不能使用jsx的語法

React項目怎么從Javascript到Typescript

這個解決很簡單,去tsconfig配置一下即可。

{     "compilerOptions":{          "jsx": "react"     }  }

jsx這個配置項有三個值可選擇,分別是"preserve","react-native"和"react"。在preserve和react-native模式下生成代碼中會保留JSX以供后續的轉換操作使用(比如:Babel)。另外,preserve輸出文件會帶有.jsx擴展名,而react-native是.js拓展名。react模式會生成React.createElement,在使用前不需要再進行轉換操作了,輸出文件的擴展名為.js。

模式輸入輸出輸出文件擴展名
preserve<div /><div />.jsx
react<div />React.createElement("div").js
react-native<div /><div />.js

webpack里面配置的alias無法解析

module.exports = {      //省略部分代碼...      resolve: {          alias:{            '@':path.join(__dirname,'../src')          }          //省略部分代碼...          },      //省略部分代碼...     }

React項目怎么從Javascript到Typescript

這里需要我們額外在tsconfig.json配置一下。

{      "compilerOptions":{          "baseUrl": ".",          "paths": {            "@/*":["./src/*"]          }       }  }

具體如何配置,請看typescript的文檔,我就不展開介紹了,但是要注意的是baseUrl和paths一定要配合使用。

https://www.tslang.cn/docs/ha...

無法自動添加拓展名而導致找不到對應的模塊

React項目怎么從Javascript到Typescript

原先我們在webpack里是這么配置的:

module.exports = {      //省略部分代碼...       resolve: {          //省略部分代碼...           extensions: ['.js', '.jsx', '.json']      },      //省略部分代碼...   }

但是我們項目里所有.js和.jsx的文件都改成了.ts和.tsx文件,因此配置需要調整。

{      //省略部分代碼...       resolve: {          //省略部分代碼...           extensions: ['.ts','.tsx','.js', '.jsx', '.json']      },      //省略部分代碼...   }

Could not find a declaration file for module '**'

這個比較簡單,它提示找不到哪個模塊的聲明文件,你就裝個哪個模塊的就好了,安裝格式如下:

yarn add @types/**

舉個?,如果提示Could not find a declaration file for module 'react',那你應該執行如下命令:

yarn add @types/react

這個僅限于第三方包,如果是項目自己的模塊提示缺少聲明文件,那就需要你自己寫對應的聲明文件了。比如你在window這個全局對象上掛載了一個對象,如果需要使用它的話,就需要做一下聲明,否則就會報錯。至于具體怎么寫,這得看typescript的文檔,這里就不展開說明了。

https://www.tslang.cn/docs/ha...

Cannot find type definition file for '**'

React項目怎么從Javascript到Typescript

這些并沒有在我們的業務代碼里直接用到,而是第三方包用到的,遇到這種情況,需要檢查一下tsconfig.json中的typeRoots這個配置項有沒有配置錯誤。一般來說是不用配置typeRoots,但是如果需要加入額外的聲明文件路徑,就需要對其進行修改。typeRoots是有一個默認值,有人會誤以為這個默認值是“["node_modules"]”,因此會有人這樣配置:

{      "compilerOptions":{          "typeRoots":["node_modules",...,"./src/types"]      }  }

實際上typeRoots的默認值“["@types"]”,所有可見的"@types"包都會在編輯過程中被加載進來,比如“./node_modules/@types/”,“../node_modules/@types/”和“../../node_modules/@types/”等等都會被加載進來。所以遇到這種問題,你的配置應該改成:

{      "compilerOptions":{          "typeRoots":["@types",...,"./src/types"]      }  }

在實際項目中,@types基本上存在于根目錄下的node_modules下,因此這里你可以改成這樣:

{      "compilerOptions":{          "typeRoots":["node_modules/@types",...,"./src/types"]      }  }

不支持decorators(裝飾器)

React項目怎么從Javascript到Typescript

typescript默認是關閉實驗性的ES裝飾器,所以需要在tsconfig.json中開啟。

{      "compilerOptions":{          "experimentalDecorators":true      }  }

Module '**' has no default export

React項目怎么從Javascript到Typescript

提示模塊代碼里沒有“export

default”,而你卻用“import from ”這種默認導入的形式。對于這個問題,我們需要把tsconfig.json配置項“allowSyntheticDefaultImports”設置為true。允許從沒有設置默認導出的模塊中默認導入。不過不必擔心會對代碼產生什么影響,這個僅僅為了類型檢查。

{      "compilerOptions":{          "allowSyntheticDefaultImports":true      }  }

當然你也可以使用“esModuleInterop”這個配置項,將其設置為true,根據“allowSyntheticDefaultImports”的默認值,如下:

module === "system" or --esModuleInterop

對于“esModuleInterop”這個配置項的作用主要有兩點:

  • 提供__importStar和__importDefault兩個helper來兼容babel生態

  • 開啟allowSyntheticDefaultImports

對于“esModuleInterop”和“allowSyntheticDefaultImports”選用上,如果需要typescript結合babel,毫無疑問選“esModuleInterop”,否則的話,個人習慣選用“allowSyntheticDefaultImports”,比較喜歡需要啥用啥。當然“esModuleInterop”是最保險的選項,如果對此拿捏不準的話,那就乖乖地用“esModuleInterop”。

無法識別document和window這種全局對象

React項目怎么從Javascript到Typescript

遇到這種情況,需要我們在tsconfig.json中lib這個配置項加入一個dom庫,如下:

{      "compilerOptions":{          "lib":[              "dom",              ...,              "esNext"          ]      }  }

文件中的標紅問題

關于這個問題,我們需要分兩種情況來考慮,***種是.ts的文件,第二種是.tsx文件。下面來看一下具體是哪些注意的點(Ps:以下提到的注意的點并不能完全解決文件中標紅的問題,但是可以解決大部分標紅的問題):

***種:.ts文件

這種文件在你的項目比較少,比較容易處理,根據實際情況去加一下類型限制,沒有特別需要講的。

第二種:.tsx文件

這種情況都是react組件了,而react組件又分為無狀態組件和有狀態組件組件,所以我們分開來看。

無狀態組件

對于無狀態組件,首先得限制他是一個FunctionComponent(函數組件),其次限制其props類型。舉個?:

import React, { FunctionComponent, ReactElement } from 'react';  import {LoadingComponentProps} from 'react-loadable';  import './style.scss';  interface LoadingProps extends LoadingComponentProps{    loading:boolean,    children?:ReactElement  }  const Loading:FunctionComponent<LoadingProps> = ({loading=true,children})=>{    return (      loading?<div className="comp-loading">        <div className="item-1"></div>        <div className="item-2"></div>        <div className="item-3"></div>        <div className="item-4"></div>        <div className="item-5"></div>      </div>:children    )    }  export default Loading;

其中你要是覺得FunctionComponent這個名字比較長,你可以選擇用類型別名“SFC”或者“FC”。

有狀態組件

對于有狀態組件,主要注意三點:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. props和state都要做類型限制

  3. state用readonly限制“this.state=**”的操作

  4. 對event對象做類型限制 

import React,{MouseEvent} from "react";  interface TeachersProps{    user:User  }  interface TeachersState{    pageNo:number,    pageSize:number,    total:number,    teacherList:{      id: number,      name: string,      age: number,      sex: number,      tel: string,      email: string    }[]  }  export default class Teachers extends React.PureComponent<TeachersProps,TeachersState> {      readonly state = {          pageNo:1,          pageSize:20,          total:0,          userList:[]      }      handleClick=(e:MouseEvent<HTMLDivElement>)=>{          console.log(e.target);      }      //...省略部分代碼      render(){          return <div onClick={this.handleClick}>點擊我</div>      }  }

實際項目里,組件的state可能會有很多值,如果按照我們上面這種方式去寫會比較麻煩,所以可以考慮一下下面這個簡便寫法:

import React,{MouseEvent} from "react";  interface TeachersProps{    user:User  }  const initialState = {    pageNo:1,    pageSize:20,    total:0,    teacherList:[]  }  type TeachersState = Readonly<typeof initialState>  export default class Teachers extends React.PureComponent<TeachersProps,TeachersState> {      readonly state = initialState      handleClick=(e:MouseEvent<HTMLDivElement>)=>{          console.log(e.target);      }      //...省略部分代碼      render(){          return <div onClick={this.handleClick}>點擊我</div>      }  }

這種寫法會簡便很多代碼,但是類型限制效果上明顯不如***種,所以這種方法僅僅作為參考,可根據實際情況去選擇。

Ant Design丟失樣式文件

當我們把項目啟動起來之后,某些同學的頁面可能會出現樣式丟失的情況,如下:

React項目怎么從Javascript到Typescript

打開控制臺,我們發現Ant Design的類名都找不到對應的樣式:

React項目怎么從Javascript到Typescript

出現這種情況是因為我們把babel刪除之后,用來按需加載組件樣式文件的babel插件babel-plugin-import也隨著丟失了。不過typescript社區有一個babel-plugin-import的Typescript版本,叫做“ts-import-plugin”,我們先來安裝一下:

yarn add ts-import-plugin -D

這個插件需要結合ts-loader使用,所以webpack配置中需要做如下調整:

const tsImportPluginFactory = require('ts-import-plugin')  module.exports = {      //省略部分代碼...      module:{          rules:[{              test: /\.tsx?$/,              loader: "ts-loader",              options: {                  transpileOnly: true,//(可選)                  getCustomTransformers: () => ({                    before: [                      tsImportPluginFactory({                          libraryDirectory: 'es',                          libraryName: 'antd',                          style: true                      })                    ]                  })              }          }]      }      //省略部分代碼...  }

這里要注意一下transpileOnly: true這個配置,這是個可選配置,我建議是只有大項目中才加這個配置,小項目就沒有必要了。由于typescript的語義檢查器會在每次編譯的時候檢查所有文件,因此當項目很大的時候,編譯時間會很長。解決這個問題的最簡單的方法就是用transpileOnly: true這個配置去關閉typescript的語義檢查,但是這樣做的代價就是失去了類型檢查以及聲明文件的導出,所以除非在大項目中為了提升編譯效率,否則不建議加這個配置。

配置完成之后,你的瀏覽器控制臺可能會報出類似下面這個錯誤:

React項目怎么從Javascript到Typescript

出現這個原因是因為你的typescript配置文件tsconfig.json中的module參數設置不對,兩種情況會導致這個問題:

  • module設置成了“commonjs”

  • target設置"ES5"但是并未設置module(當target不為“ES6”時,module默認為“commonjs”)

解決這個辦法就是把module設置為“esNext”便可解決這個問題。

{      "compilerOptions":{          "module":"esNext"      }  }

可能會有小伙們說設置成“ES6”或者“ES2015”也是可以的,至于我為什么選擇“esNext”而不是“ES6”或者“ES2015”,主要原因是設置成“ES6”或者“ES2015”之后,就不能動態導入了,因為項目使用了react-loadable這個包,要是設置成“ES6”或者“ES2015”的話,會報如下這個錯誤:

React項目怎么從Javascript到Typescript

typescript提示我們需要設置成“commonjs”或者“ESNext”才可動態導入,所以保險起見,我是建議大家設置成ESNext。完成之后我們的頁面就可以正常顯示了。

React項目怎么從Javascript到Typescript

說到module參數,這里要再多提一嘴說一下moduleResolution這個參數,它決定著typescript如何處理模塊。當我們把module設置成“esNext”時,是可以不用管moduleResolution這個參數,但是大家項目里要是設置成“ES6”的話,那就要設置一下了。先看一下moduleResolution默認規則:

module === "AMD" or "System" or "ES6" ? "Classic" : "Node"

當我們module設置為“ES6”時,此時moduleResolution默認是“Classic”,而我們需要的是“Node”。為什么要選擇“node”,主要是因為node的模塊解析規則更符合我們要求,解析速度會更快,至于詳情的介紹,可以參考Typescript的文檔。

“React項目怎么從Javascript到Typescript”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

塔城市| 和政县| 揭阳市| 宁津县| 丰县| 宁波市| 郯城县| 佛山市| 龙山县| 巨野县| 邯郸县| 黎平县| 和林格尔县| 沾益县| 辉南县| 儋州市| 沙田区| 建宁县| 赫章县| 伊吾县| 阿尔山市| 灵宝市| 富顺县| 凤山市| 手机| 丹东市| 武平县| 临邑县| 浦东新区| 宁津县| 二连浩特市| 五常市| 柏乡县| 石柱| 安乡县| 响水县| 朔州市| 岳池县| 深圳市| 麦盖提县| 公安县|