技术/前端/Typescript
Typescript
作为Javascript类型的超集,赋予我们在开发Javascript程序时使用高效的开发工具和常用操作的能力,比如类型检查、代码重构。并且使用Typescript实现的代码可以编译出纯净、简洁的Javascript,可直接运行在任何浏览器、Node.js环境中以及任何支持ECMAScript3的Javascript引擎,这可以让我们在任何终端机器上都可以运行我们的Typescript代码。
开始使用
安装
npm install -g typescript
编译
tsc hello.ts
感受编译示例:
TS + React
今天,我们不去关注TS复杂的类型系统,而是直接来看,如何使用TS来实现React常见的使用场景,包括props
、hooks
和render 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是一个函数,接收参数最后返回一个null
或React.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类组件,记得关注我的公号【也寻常】,顺便聊点别的~