前置阅读:TypeScript 中文网
目录
- React项目集成TS
- 集成流程概览
- 安装依赖
- 为什么不使用ts-loader
- bebel.config.json修改
- webpack修改
- .eslintrc修改
- package.json配置
- 声明文件的作用
- TS在项目中应该怎么去写?
- 应用到哪些地方?
- 怎么应用 ?(附todoList项目源码)
React项目集成TS
集成流程概览
安装依赖
@babel/preset-typescript 是babel转义ts
@types/react @types/react-dom 是react依赖的类型库
@types/webpack-env 是webpack的全局属性类型库
yarn add typescript @babel/preset-typescript @types/react @types/react-dom @types/webpack-env -D
复制代码
为什么不使用ts-loader
- 只管理一个编译器更轻松
- babel更快,原因具体可见 为什么说用 babel 编译 typescript 是更好的选择
- babel加了 polyfills 做了低版本的兼容处理,而tsloader没有
当然是有缺点的,但是缺点可以避免,总收益是大的所以就用babel
- 无法实时完成项目的类型检查,检查提示错误是IDE的提示,这个优化方法 就是每次开发完成后 执行一下类型检查
tsc -noEmit
bebel.config.json修改
{
"presets": ["@babel/env", "@babel/preset-react", "@babel/preset-typescript"], // 新增
"plugins": ["react-hot-loader/babel"]
}
复制代码
webpack修改
全部react文件更名为TSX格式 原因是tsx语义更强
module.exports = (env, args) => {
// prd 模式
const cssTypePrd = args.env.css === 'prd'
return {
entry: './app.tsx', // 入口文件
module: {
rules: [ // 配置加载器
{
test: /\.(jsx|tsx|js|ts)?$/,// 处理es6语法以及jsx语法
loader: 'babel-loader',
include: [
path.resolve(__dirname, 'src'), // 使用目录
path.resolve(__dirname, 'app.tsx'), // 使用文件
],
},
]
},
resolve: { // 新增因为现在的文件变为了 tsx 和ts后缀名所以需要增加两个后缀名 tsx和ts
extensions: ['.tsx', '.ts', '.json', '.js'], // 尝试按顺序解析这些后缀名。如果有多个文件有相同的名字,但后缀名不同,webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀。
},
}
}
复制代码
.eslintrc修改
{
"extends": [
"eslint-config-ali",
"eslint-config-ali/react",
"eslint-config-ali/typescript", // 修改项
"eslint-config-ali/typescript/react" // 修改项
],
"rules": {
"semi": [2, "never"],
"no-console": "off",
"react/no-array-index-key": "off",
"react/prop-types":"off"
},
"globals": { // 修改项
"GLOBAL_ENV": true
},
"ignorePatterns": [ // 忽略文件夹
"dist",
"node_modules",
"*.d.ts"
]
}
复制代码
ts-config.json 文件
虽然不需要ts-loader来进行转译,但是需要ts-config的配置和IDE协作
{
"compilerOptions": { // 编译配置
"jsx": "react",
"types": ["node", "react", "react-dom", "webpack-env"], // 获取node_modules下的@types下的ts依赖,不写就算add type也没用
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出,仅为了类型检查
"noEmit": true, // 不生成文件,只做类型检查
},
}
// 参考链接 https://segmentfault.com/a/1190000021421461
// https://juejin.cn/post/6844904052094926855#heading-17
// 这里没用ts-loader所以tsconfig的作用只有给IDE提示
复制代码
package.json配置
"typeCheck": "tsc --noEmit" // 新增 ts类型检查命令 不生产输出文件
复制代码
声明文件的作用
在完成这些后会发现less 还有 img文件的import会标红,因为这些文件都需要类型声明 还有全局变量
新建一个 externals.d.ts
declare module '*.less' { // less报错
const classes: { [className: string]: string };
export default classes;
}
// 文件报错声明
declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'
// 全局变量
declare var GLOBAL_ENV: string;
复制代码
TS在项目中应该怎么去写?
TS的目的是为了更安全高效的类型提示和检查
应用到哪些地方?
基础知识是哪些?
函数类型接口以及类型别名
-
两者区别
名称 不同点 相同点 interface 没有联合类型 以及 元组 都可以描述对象和函数,都允许扩展 type 无法声明合并 都可以描述对象和函数,都允许扩展
泛型
-
函数泛型
function test<T>(name:T) => { console.log(name) } test<string>('小明') 复制代码
-
class泛型
class Test<T>{ constructor(params:T) { console.log(params) } } new Test<Number>(1) 复制代码
-
interface泛型
interface Test<T> { name: string, age: number, info: T } const test:Test<string> = { name: '小米', age:11, info: '我是一个学生' } 复制代码
枚举
-
维护常量
- 建议写法
enum Test { NAME = 'name', AGE = 'age', } 复制代码
typeof 与 keyof 的用法
-
typeof
-
给枚举以及 定义类型的值用
const a: number = 3 // 相当于: const b: number = 4 const b: typeof a = 4 复制代码
-
-
keyof
-
只能给类型用
interface Point { x: number; y: number; } // type keys = "x" | "y" type keys = keyof Point; 复制代码
-
怎么应用 ?
写一个简单的todoList
- 函数组件定义
- 函数组件的props定义
- hooks的定义
- 自己方法的定义
注意的坑有?
- class组件的defaultprops 无法和props的类型相关联,但是函数组件可以 ,参考链接, (可以看一下当前的 react的定义类型文件。)
- chilren的定义 需要 写 React.ReactNode ,其他 ReactNodeArray 与 ReactChild 无法容错
- 函数组件如果使用
React.FC
类型无法直接返回 Arr.map 结构,因为Arr.map有可能返回为[]
扩展阅读
TS的内置函数
TS的lib 声明文件 有一些内置的工具函数可以用
-
Partial
// 让对象属性的所有属性都是可选的 interface User { name: string, age: number } /* * { name?: string, age?:string } */ type Test = Partial<User> 复制代码
-
Required
// 全部属性转为必需属性 interface User { name?: string, age?: number } /* * { name: string, age:string } */ type Test = Required<User> 复制代码
-
Readonly
// 全部属性转为只读属性 interface User { name: string, age: number } /* * { readonly name: string, readonly age:string } */ type Test = Readonly<User> 复制代码
-
Pick
// 获取全部对象类型某个属性 interface User { name: string, age: number } /* * { name: string, } */ type Test = Pick<User, 'name'> 复制代码
-
Record
// 对象类型中赋给某个新的对象类型 interface User { name: string, age: number } /* * { test: User, } */ type Test = Record<'test', User> 复制代码
-
Omit
// 对象类型排除某个属性 // 对象类型中赋给某个新的对象类型 interface User { name: string, age: number } /* * { name: string, } */ type Test = Omit<User, 'age'> 复制代码
TS的?
和!
操作符用法
TypeScript中的问号 ? 与感叹号 ! 是什么意思?
参考链接
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END