在React应用程序中进行静态输入

2016年,TypeScript开始崭新的高度。 开发人员开始完全重写许多流行的技术,并在现有平台上增加对静态分析的支持。 这样的全局过程为成千上万甚至数万个项目的代码库增加了更多的稳定性。

为什么要反应 迄今为止,该库无疑在竞争者的背景下占主导地位。 在React周围,已经形成了世界上最大的开发者社区。 每三个SPA都在此平台上编写。 还有许多伟大的项目与使用React Native有关,React Native是基于React.js的iOS,UWP和Android应用程序平台。

因此,今天我们将看一下两种超级流行工具的集成所带来的可能性:TypeScript和React。



例子


首先,让我们看看我们可以为React使用什么类型。
让我们开始简单并将类型添加到功能组件中。

import * as React from 'react'; const HelloWorld: React.FunctionComponent<{ name: string; }> = ({ name = 'World' }) => { return <div>Hello, {props.name}</div>; }; export default HelloWorld; 

对于功能组件或无状态组件,我们必须使用React.FunctionComponent类型的定义。 我们还可以为props参数定义类型-组件传递给组件的字段。 在这种情况下,道具只能包含字符串类型的名称字段。

所有这些看起来并不复杂。 那么类组件呢?

 import * as React from 'react'; interface State { name: string; } interface Props {} class HelloWorld extends React.Component<Props, State> { state = { name: 'World' } setName(name: string) { this.setState({ name }); } redner() { return ( <React.Fragment> <hI>Hello, {this.state.name}</hI> <input value={this.state.name} onChange={(e) => this.setName(e.target.value)} /> </React.Fragment> ); } } 

在类示例中,我们创建了两个接口:Props和State。 在他们的帮助下,我们确定了传入道具的签名(空)和组件状态的签名-如功能组件的示例中所示。

我们还可以添加默认道具值。

 import * as React from 'react'; interface Props { name?: string; } export default class HelloWorld extends React.Component<Props> { static defaultProps: Props = { name: 'World' }; render () { return <hI>Hello, {this.props.name}</hI>; } } 

仅此而已! 我们的小型React应用程序已经在参数和组件状态值的级别上进行了强类型化。

让我们看一下这给我们带来的好处:

  • 在编译阶段,我们将看到所有类型的不匹配;
  • 正确配置的编辑器将仅突出显示签名或数据类型的差异,即使在开发阶段也将帮助我们避免错误;
  • 接口和类型定义的文档。


枚举参数



枚举是一种枚举数据类型。 如果我们将此类型添加到变量或接口字段中,则此字段或变量的值只能是Enum中的特定值。
举个例子

  import * as React from 'react'; enum Colors { RED, BLUE, GREEN } const ColorResult: React.FunctionComponent<{ color: Colors; }> = ({ color = Colors.Red }) => { return <div>Your color is {props.color}</div>; }; export default ColorResult; 

在我们已经知道的功能组件中,我们想显示用户选择的颜色。 在枚举颜色类型中,我们指定了可以传输到组件的所有可能的颜色选项。 如果TypeScript编译器在某处发现类型不匹配,则会向您显示此错误。

严格的Redux


在2019年,我们仍将在Redux上运行许多应用程序。 在这种情况下,TypeScript可以提供帮助。

 import * as React from 'react'; const initialState = { name: 'World' }; type HelloWorldStateProps = Readonly<typeof initialState>; interface Action { type: string; name?: string; } const worldNameReducer = ( state: HelloWorldStateProps = initialState, action: Action ): HelloWorldStateProps => { switch (action.type) { case "SET": return { name: action.name }; case "CLEAR": return { name: initialState.name }; default: return state; } }; const set = (name): Action => ({ type: "SET", name }); const clear = (): Action => ({ type: "CLEAR" }); const store = createStore( combineReducers({ world: worldNameReducer }) ); type StateProps = ReturnType<typeof mapStateToProps>; type DispatchProps = typeof mapDispatchToProps; interface AppProps extends StateProps, DispatchProps {} interface AppState extends StateProps {} class App extends React.Component<AppProps, AppState> { state = { name: initialState.name } setName(name: string) { this.setState({ name }); } render() { const { set, clear, name } = this.props; return ( <div> <hI>Hello, {name}</hI> <input value={this.state.name} onChange={(e) => this.setName(e.target.value)} /> <button onClick={() => set(this.state.name)}>Save Name</button> <button onClick={() => clear()}>Clear</button> </div> ); } } const mapStateToProps = ({ world }: { world: HelloWorldStateProps }) => ({ name: world.name, }); const mapDispatchToProps = { set, clear }; const AppContainer = connect( mapStateToProps, mapDispatchToProps )(App); render( <Provider store={store}> <AppContainer /> </Provider>, document.getElementById("root") ); 

在此示例中,我们在多个级别上一次向应用程序添加类型。 首先,它是减速器本身。 输入reducer接受Action,并且它必须始终返回与HelloWorldStateProps类型匹配的对象。 考虑到现代应用中有多少个减速器,这是非常有用的创新。 此外,我们拥有的每个动作都有严格的动作签名。

下一个键入级别是component。 在这里,我们将类型继承应用于AppProps和AppState。 当我们已经具有带有此类签名的数据类型时,为什么还要编写更多内容? 维护系统更容易。 如果更改某些元素,则所有继承人都将发生更改。

结论


TypeScript是在JavaScript之上运行的一种非常有用的语言。 结合React,它为Frontend应用程序提供了令人印象深刻的编程实践。

Source: https://habr.com/ru/post/zh-CN465461/


All Articles