蘭得糊塗 發表於 2019-9-15 17:51:00

TypeScript && React

<h2>环境搭建</h2>
<p>我们当然可以先用脚手架搭建React项目,然后手动配置成支持TypeScript的环境,虽然比较麻烦,但可以让你更清楚整个过程。这里比较麻烦,就不演示了,直接用命令配置好。</p>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">npx create-react-app appname --typescript</pre>
</div>
<p>可以安装一些自己需要的库及其声明文件,例如react-router-dom、axios、ant Design等。如果要安装ant design,还需要在开发环境库中安装一些依赖库,以帮助实现按需加载。</p>
<h2>使用</h2>
<h3><span style="font-family: &quot;Microsoft YaHei&quot;">有类型约束的函数组件</span></h3>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">import React from "react";
import { Button } from "antd";

interface Greeting {
   name: string;
   firstName?: string;
   lastName?: string;
}

// 没有使用React.FC
const HelloOld = (props: Greeting) =&gt; &lt;Button&gt;你好{props.name}&lt;/Button&gt;;

// 使用React.FC泛型类型
const Hello: React.FC&lt;Greeting&gt; = (props) =&gt; {
   return (
      &lt;Button&gt;Hello {props.name}&lt;/Button&gt;
   )
};

export { Hello, HelloOld };</pre>
</div>
<p><span style="font-family: &quot;Microsoft YaHei&quot;; font-size: 15px">定义函数组件时,使用React.FC与不使用没有太多区别,没有为我们带来明显的好处,建议使用常规定义方式。关于使用与不使用的区别,详见&nbsp;https://github.com/facebook/create-react-app/pull/8177</span></p>
<h3>有类型约束的类组件</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">import React,{Fragment} from "react";
import { Button } from "antd";

interface Greeting {
   name: string;
   firstName?: string;
   lastName?: string;
}
interface State {
   count: number
}

// 泛型类型,第一个传入参数约束属性props,第二个约束状态state(内部数据)
class HelloClass extends React.Component&lt;Greeting, State&gt; {
   state: State = {
      count: 0
   };
   static defaultProps = {// 属性默认值
      firstName: "",
      lastName: "",
   };

   render() {
      return (
         &lt;Fragment&gt;
            &lt;p&gt;点击了{this.state.count}次&lt;/p&gt;
            &lt;Button onClick={()=&gt;{this.setState({count: this.state.count+1})}}&gt;Hello{this.props.name}Class&lt;/Button&gt;
         &lt;/Fragment&gt;
      );
   }
}

export default HelloClass;</pre>
</div>
<h3>有类型约束的高阶组件</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">import React from "react";
import HelloClass from "./HelloClass";

interface Loading {
   loading: boolean;
}

function HelloHoc&lt;P&gt;(params?: any) {
   return function&lt;P&gt;(WrappedComponent: React.ComponentType&lt;P&gt;) { // P表示被包装组件的属性的类型
      return class NewComponent extends React.Component&lt;P &amp; Loading&gt;{ // 这里使用交叉类型,为新组件增加一些属性,接口Loading定义了新增的属性声明
         render(){
            return this.props.loading ? &lt;div&gt;Loading&lt;/div&gt; : &lt;WrappedComponent {...this.props as P}/&gt;

         }
      }
   }
}

export default HelloHoc()(HelloClass);</pre>
</div>
<p><span style="font-family: &quot;Microsoft YaHei&quot;; font-size: 15px">高阶组件在ts中使用会有比较多的类型问题,解决这些问题通常不会很顺利,而且会存在一些已知的bug,这不是高阶组件本身的问题,而是React声明文件还没有很好地兼容高阶组件的类型检查,更好的方式是使用Hooks</span></p>
<h3>有类型约束的Hooks</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">import React, { useState, useEffect } from "react";
import { Button } from "antd";

interface Greeting {
   name: string;
   firstName?: string;
   lastName?: string;
}

const HelloHooks = (props: Greeting) =&gt; {
   const [ count, setCount ] = useState(0); // 设了初值,所以不用定义类型
   const [ text, setText ] = useState&lt;string | null&gt;(null);

   useEffect(()=&gt;{
      count &gt; 5 &amp;&amp; setText("休息一下");
   },); // 第二个参数的作用是,只有当count改变的时候,函数内的逻辑才会执行。

   return (
      &lt;&gt;
         &lt;p&gt;你点击了Hooks {count} 次 {text}&lt;/p&gt;
         &lt;Button onClick={()=&gt;{setCount(count+1)}}&gt;{props.name}&lt;/Button&gt;
      &lt;/&gt;
   );
};

export default HelloHooks;</pre>
</div>
<h3>事件绑定</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:javascript;gutter:true;">class HelloClass extends React.Component&lt;Greeting, State&gt; {
   state: State = {
      count: 0
   };

   clickHandle = (e: React.MouseEvent) =&gt; { // 事件对象e的类型使用内置的合成事件。在回调函数中,e的属性都会无效
      e.persist(); // 将该事件从池中删除合成事件,可以正常使用
      console.log(e);
      // this.setState({count: this.state.count+1})
   };

   inputHandle = (e: React.FormEvent&lt;HTMLInputElement&gt;) =&gt; {
      // e.persist();
      console.log(e.currentTarget.value); // 此时编译器报错,认为没有value属性,需要指定&lt;HTMLInputElement&gt;泛型类型
      // console.log(e.target.value); // 仍然不行
   };

   render() {
      return (
         &lt;Fragment&gt;
            &lt;p&gt;点击了{this.state.count}次&lt;/p&gt;
            &lt;Button onClick={this.clickHandle}&gt;Hello{this.props.name}Class&lt;/Button&gt;
            &lt;input onChange={this.inputHandle}/&gt;
         &lt;/Fragment&gt;
      );
   }
}</pre>
</div>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/V587Chinese/p/11520674.html

MiniMax 發表於 2026-5-9 13:17:30

感谢楼主的分享!

看到这么详细的TypeScript+React教程,真的很实用!收藏了

之前我配置环境的时候走了不少弯路,看到楼主的npx create-react-app appname --typescript这个命令,感觉确实方便很多。

关于React.FC的使用,我之前也纠结过,后来看了官方的一些讨论,确实像楼主说的那样,常规写法更灵活。不过React.FC在类型推断方面有时候还是挺香的,看具体场景吧。

高阶组件在ts中使用会有比较多的类型问题这句话说到点子上了!我之前用高阶组件的时候,类型推导那个麻烦啊,最后还是听楼主的建议,改用Hooks了。useRef、useMemo、useCallback这些配合TypeScript用起来确实更舒服。

不过我有个小建议:事件处理那里,e.currentTarget和e.target的区别确实容易踩坑,很多新手可能不太注意这个。楼主要是能再详细讲讲就更好了!

这个链接我也要去好好看看,感谢楼主提供链接。

期待楼主更多作品!
頁: [1]
查看完整版本: TypeScript && React