目录
- 1,搭建项目
- 2,tsconfig.json 相关配置项
- 1, lib
- 2,module
- 3,jsx
- 3,在 React 中使用 TS
- 3.1,TS 可以解决的问题
- 3,2,函数式组件
- 3.3,类组件
- 3.4,Props 的默认值
- 方法1
- 方法2
1,搭建项目
选用 create-react-app@5.0.1 版本。
集成 typescript 的方法,create-react-app 文档中有介绍。运行如下命令即可:
npx create-react-app my-app --template typescript
2,tsconfig.json 相关配置项
compilerOptions
是编译选项,include
是编译目录。
{
"compilerOptions": {
"target": "es5", // 编译后的 js 版本。
"lib": [ // 开发(写TS)时允许使用的库。
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true, // 允许在 ts 中引入 js 文件。
"skipLibCheck": true, // 跳过对声明文件的类型检查。
"esModuleInterop": true, // 启用 es 模块化交互,可以引入那些使用非 es 导出的模块。
"allowSyntheticDefaultImports": true, // 和上面是匹配出现的。
"strict": true, // 开启严格模式(统一将 strictNullChecks 等严格检查配置项都开启。)
"forceConsistentCasingInFileNames": true, // 强制检查导入文件时,文件名的大小写需一致。
"noFallthroughCasesInSwitch": true,
"module": "esnext", // 设置编译结果中,使用的模块化标准。esnext 就是最新版
"moduleResolution": "node", // 模块解析策略(查找文件的步骤)
"resolveJsonModule": true, // 允许导入 json 文件,将其作为对象使用。
"isolatedModules": true, // 将每一个文件都当做一个模块(每个文件中必须得有导出或导入语句,语法受 module 影响),
"noEmit": true, // 不生成 js 文件,在内存中完成 ts-->js 的过程(因为后面还有 babel 处理)。
"jsx": "react-jsx" // 如何处理 jsx 语法。
},
"include": [
"src"
]
}
esModuleInterop
和 moduleResolution
的含义都可以看这篇文章。
1, lib
1,dom
,允许使用 DOM 环境下的对象,比如 document
对象
2,dom.iterable
,允许使用 dom 对象的迭代器。
es6 之后,新增了一个内置对象 Symbol,它是基本数据类型。同时还有一些静态属性,其中之一就是 Symbol.iterator 。
for…of 就是用于循环可迭代的对象。换句话说,只要对象有迭代器才能使用 for…of 循环。比如常见的:字符串,Array
,Map
,Set
,DOM 对象等。
但 ts 限制的更加严格,默认情况下,for...of
只能循环字符串和Array
,如果想循环其他的对象,需要增加配置选项:"downlevelIteration": true
。
3,esnext,允许使用最新版的 js。
2,module
注意,脚手架搭建的项目中,是使用 webpack + ts + babel 来联合处理的:
1,webpack 加载 ts --> 2,typescript 编译 ts 为 js --> 3,babel 将高版本 js 编译为低版本的。
而 module
选项影响的是第2步。所以项目最终打包的结果中 js 并不是 module 指定的最新版 js。
3,jsx
表示 ts 如何处理 jsx
语法。注意处理完成后的 js 文件还是会交给 babel 处理。
ts官方文档
Mode | Input | Output | Output File Extension |
---|---|---|---|
preserve | <div /> |
<div /> |
.jsx |
react | <div /> |
React.createElement("div") |
.js |
react-native | <div /> |
<div /> |
.js |
react-jsx | <div /> |
_jsx("div", {}, void 0); |
.js |
react-jsxdev | <div /> |
_jsxDEV("div", {}, void 0, false, {...}, this); |
.js |
3,在 React 中使用 TS
3.1,TS 可以解决的问题
- 组件有哪些属性可以传递,属性的类型是什么;
- 事件传递时的参数;
- 运行时的错误。
虽然可以通过propTypes
约束属性的类型,但这是在运行时才能发现。而 TS 是一套静态的类型系统,所以在开发时就能发现错误。
3,2,函数式组件
interface IProps {
num: number;
onChange?: (num: number) => void;
}
export const CompCount: React.FC<IProps> = function (props) {
return (
<div>
<button
onClick={() => {
if (props.onChange) {
props.onChange(props.num - 1);
}
}}
>
减一
</button>
<span>{props.num}</span>
</div>
);
};
其中 React.FC
是一个类型别名,用于约束函数式组件的,泛型 P
是 Props 的类型。
type FC<P = {}> = FunctionComponent<P>;
所以也可以直接写:
import { FunctionComponent } from "react";
export const CompCount: FunctionComponent<IProps> = function (props) {}
或者,用TS基础的类型约束方式:
export function CompCount(props:IProps) {}
3.3,类组件
import React from "react";
interface IProps {
num: number;
onChange?: (num: number) => void;
}
interface IState {
msg: string;
desc: string;
}
export class CompCount extends React.Component<IProps, IState> {
state = {
msg: "init",
desc: "",
};
render() {
return (
<div>
<button
onClick={() => {
if (this.props.onChange) {
this.props.onChange(this.props.num - 1);
}
}}
>
减一
</button>
<span>{this.props.num}</span>
</div>
);
}
}
其中 React.Component
是类组件的接口,用于约束类组件。泛型 P
是 Props 的类型,S
是 State 的类型。
interface Component<P = {}, S = {}, SS = any> extends ComponentLifecycle<P, S, SS> {}
3.4,Props 的默认值
方法1
因为 Props 通过接口约束了,可接口无法指定字段的默认值。可通过组件的 defaultProps
属性来指定。
FunctionComponent
接口定义的字段:
interface FunctionComponent<P = {}> {
(
props: P,
deprecatedLegacyContext?: any,
): ReactNode;
propTypes?: WeakValidationMap<P> | undefined;
contextTypes?: ValidationMap<any> | undefined;
defaultProps?: Partial<P> | undefined;
displayName?: string | undefined;
}
步骤:
1,把要赋默认值的字段改成可选的。
2,,设置组件的 defaultProps
属性,指定默认值即可。
interface IProps {
num?: number;
}
export const CompCount: React.FC<IProps> = function (props) {
return (
<div>{props.num! - 1}</div>
);
};
CompCount.defaultProps = {
num: 2,
};
此时会有一个问题,这个 num
可能为 undefined
,所以需要使用非空断言 !
num! // 表示 num 一定不是 null 或 undefined
// 或重新定义一个变量来使用。
const _num = props.num as number
方法2
其他通过指定 defaultProps
的方式,React 已经不推荐了(当前测试版本 v18.3.1),更推荐使用解构赋值的方式,直接指定默认值。
interface IProps {
num?: number; // 注意同样得设置为可选属性。
onChange?: (num: number) => void;
}
export const CompCount: React.FC<IProps> = function ({num = 2, onChange}) {
return (
<div>{num - 1}</div>
);
};
以上。