React 中使用 TS

目录

  • 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,搭建项目

选用 [email protected] 版本。

集成 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"
  ]
}

esModuleInteropmoduleResolution 的含义都可以看这篇文章。

1, lib

1,dom,允许使用 DOM 环境下的对象,比如 document 对象

2,dom.iterable,允许使用 dom 对象的迭代器。

es6 之后,新增了一个内置对象 Symbol,它是基本数据类型。同时还有一些静态属性,其中之一就是 Symbol.iterator 。

for…of 就是用于循环可迭代的对象。换句话说,只要对象有迭代器才能使用 for…of 循环。比如常见的:字符串,ArrayMapSet ,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
.jsx
react
React.createElement("div") .js
react-native
.js
react-jsx
_jsx("div", {}, void 0); .js
react-jsxdev
_jsxDEV("div", {}, void 0, false, {...}, this); .js

3,在 React 中使用 TS

3.1,TS 可以解决的问题

  1. 组件有哪些属性可以传递,属性的类型是什么;
  2. 事件传递时的参数;
  3. 运行时的错误。
    虽然可以通过 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>
    );
};

以上。

你可能感兴趣的:(typescript,react,前端,typescript,react)