技术/前端/Typescript

Typescript作为Javascript类型的超集,赋予我们在开发Javascript程序时使用高效的开发工具和常用操作的能力,比如类型检查、代码重构。并且使用Typescript实现的代码可以编译出纯净、简洁的Javascript,可直接运行在任何浏览器、Node.js环境中以及任何支持ECMAScript3的Javascript引擎,这可以让我们在任何终端机器上都可以运行我们的Typescript代码。

image.png

开始使用

安装

  1. npm install -g typescript

编译

tsc hello.ts

感受编译示例:
A12C46DA-37EE-447B-8F03-A7E6E37D92CC.png

TS + React

今天,我们不去关注TS复杂的类型系统,而是直接来看,如何使用TS来实现React常见的使用场景,包括propshooksrender props, let’s go !

使用create-react-app创建一个支持typescript的react项目,注意:低版本的cra可能会创建失败,项目结构缺失或不完整,更新后即可使用

create-react-app ts-react-demos --typescript

首先,创建一个App.tsx组件:

import React from 'react';

const App = () => {
    return <div>app</div>;
}

export default App;

这是很简单的一个函数式组件,现在我们使用TS来改造一下:

import React from 'react';

// App作为函数,指定函数类型, `React.FC`表示React FunctionComponent
const App: React.FC= () => {
    return <div>app</div>;
}

export default App;

Props

现在,让我们来创建一个输入框组件TextField.tsx:

import React from 'react';
export const TextField = () => {
    return (
        <div>
            <input />
        </div>
    )
};

这是一个简单的组件,可以经过TS改造,两步走:

  • 函数组件增加类型,React.FC
  • 组件props增加类型,接收一个text字符类型
import React from 'react';
export const TextField: React.FC<{text: string}> = () => {
    return (
        <div>
            <input />
        </div>
    )
};

上面的写法TextField: React.FC<{text: string}>指定了组件的类型,另外指定了props参数的字段及类型,当需要增加prop时,我们可以继续添加,如:<{text: string, count: number}>,但这样会给组件阅读带来困扰,现在来使用interface接口类型来定义props:

interface Props {
    text: string;
}

现在看看重新改造的TextField组件:

import React from 'react';
interface Props {
    text: string;
}
export const TextField: React.FC<Props> = () => {
    return (
        <div>
            <input />
        </div>
    )
};

现在props的interface还比较简单,现在尝试定义一些更复杂的props

interface Person {
    firstName: string;
    lastName: string;
}
interface Props {
    text: string;
    person: Person;
    // 增加可选参数
    onChange?: () => string;
}

?用来表示参数字段为可选参数。

现在我们可以在App.tsx组件中使用TextField组件:

import React from 'react';
import TextField from './TextField';
// App作为函数,指定函数类型, `React.FC`表示React FunctionComponent
const App: React.FC= () => {
    return <TextField text='text' person={{firstName: 'Jack', lastName:'Lee'}}/>;
}

export default App;

Hooks

上面已经实现了给组件的props增加类型检查,现在来尝试在组件内使用useState

import React from 'react';
interface Person {
    firstName: string;
    lastName: string;
}
interface Props {
    text: string;
    person: Person;
    // 增加可选参数
    onChange?: () => string;
}

// 定义state接口
interface TextState {
    count: number
}
export const TextField: React.FC<Props> = () => {
    const [count, setCount] = useState<TextState>({count: 0});
    return (
        <div>
            <input />
        </div>
    )
};

上面我们同样给setState增加了参数类型接口,组件有个input,可不可以增加一个ref并增加类型检查呢,试一下:

//...
const inputRef = useRef<HTMLInputElement>();
return (<div>
    <input ref={inputRef}/>
</div>)

现在如何给input增加事件处理呢,上面我们已经定义了onChange函数,现在需要给函数定义增加参数类型:

onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;

render-props

现在我们来创建一个Counter组件,这个组件接收一个render-props:

import React, { useState } from 'react';
export const Counter: React.FC<Props> = ({children}) => {
    const [count, setCount] = useState(0);
    return <div>{children(count, setCount)}</div>;
}

然后给children增加参数类型,首先children是一个函数,接收参数最后返回一个nullReact.Element

interface Props {
    children: (data: {
        count: number,
        setCount: React.Dispatch<React.SetStateAction<number>>
    }) => JSX.Element | null;
}

其中setState作为React返回的React.SetStateAction,可以在编辑器中通过Go to definition查看。

看看如何使用该组件:

import React from 'react';
import TextField from './TextField';
// App作为函数,指定函数类型, `React.FC`表示React FunctionComponent
const App: React.FC= () => {
    return <Counter>
        { ({count, setCount}) => (
            <div>
                <span>{count}</span>
                <button onClick={() => setCount(count + 1)}>+</button>
            </div>
        )}
    </Counter>;
}

export default App;

总结

我们覆盖的React使用场景:

  • props
  • hooks
  • render props

我们使用到的TS类型:

  • number/string
  • interface
  • 可选参数
  • 函数类型/事件回调函数

文章涉及到的超纲内容有HTMLInputElement, React.SetStateAction等,感兴趣的同学可以自己探索。

下一步,我会研究如何使用TS的类类型来开发React类组件,记得关注我的公号【也寻常】,顺便聊点别的~
qrcode_for_gh_3185024eec7a_258.jpg