• useState hook 是一个泛型函数,接收一个类型变量来指定状态的类型
// 指定 name 状态的类型为:string
const [name, setName] = useState<string>('jack');
// 指定 age 状态的类型为:number
const [age, setAge] = useState<number>(28);
  • 注意:该类型变量,不仅指定了状态的类型,也指定了 setName 等修改状态函数的参数类型
const [name, setName] = useState<string>('jack');
// 此时,setName 的参数的类型也是 string
setName('rose');
// 错误演示:
// setName(18)

省略类型变量,简化 useState 的调用:

  • 在使用 useState 时,只要提供了初始值,TS 就会自动根据初始值来推断出其类型,因此,可以省略类型变量
  • 注意:如果 TS 自动推断出来的类型不准确,还得显式指定泛型类型
const [name, setName] = useState('jack');

3. useState 明确指定泛型类型

目标: 能够明确指定 useState 的泛型类型

  • 需求:获取频道列表数据并渲染
// 比如,频道列表数据是一个数组,所以,在 JS 中我们将其默认值设置为:[]
// 但是,在 TS 中使用时,如果仅仅将默认值设置为空数组,list 的类型被推断为:never[],此时,无法往数组中添加任何数据
const [list, setList] = useState([]);
  • 注意:useState 的初始值是数组、对象等复杂的数据类型,需要明确指定泛型类型
    • 因为虽然都是数组、对象,但是,项目开发中不同需求所需要的数组结构、对象结构是不同的。因此,需要明确指定其类型
type Channel = {
  id: number;
  name: string;
// 明确指定状态的类型,此时,list 的类型为:Channel[]
// Channel[] 表示 Channel 类型的数组,也就是,数组中只能出现 Channel 类型的数据
const [list, setList] = useState<Channel[]>([]);
  • 使用 TS 时,应该以类型化思维来写代码,简单来说: 先有类型,再写逻辑代码来使用该类型的数据
  • 比如,对于 对象、数组 来说,就应该在使用前先明确指定要用到的对象的类型、数组的类型等等

4. TS 类型-never 类型

目标 :能够知道 TS 中 never 类型的含义

  • never 类型:永远不会出现的值的类型(或永远不会发生的类型)
  • never 类型:处理 TS 类型系统的最底层
    • 可以将 never 类型的数据,赋值给任意其他的类型;无法将任何类型(除了 never 类型自己)来分配给 never 类型
let fn = () => { // 手动通过 throw 抛出一个异常(错误) throw new Error('err...'); let n = fn(); // n => never let fn = () => { while (true) {} let n = fn(); // n => never const num = 123; if (num !== 123) { let n = num; // n => never

5. useRef 的使用

目标: 能够使用 useRef 配合 TS 操作 DOM

  • useRef hook 接收一个类型变量,用于指定 current 属性的类型
// 假设操作的是 input 标签,则指定类型为:HTMLInputElement
const inputRef = useRef<HTMLInputElement>(null)
// 此时,把鼠标放在变量 inputRef 上,也可以看到 inputRef.current 属性的类型为: HTMLInputElement | null
// 其中,HTMLInputElement 是我们明确指定的类型,而 null 是参数的类型。因为在创建 ref 对象时,JSX 对应的 DOM 还没有创建,所以,参数默认值先指定为 null
// JSX 中使用 ref:
<input ref={inputRef} />

使用 ref 对象,获取进行 DOM 操作:

  • 注意:因为 current 属性的类型是: HTMLInputElement | null ,所以,必须要从类型中“去掉” null 才能继续操作
  • 可以使用 JS 中的 可选链操作符(?.) 来实现:
  • 原理: ?. 会判断 current 属性是否为空值(null 或 undefined),如果不是空值,就继续访问 value 值;如果是空值,不会继续访问 value
    • 如果 current 不是空值,其类型为 HTMLInputElement ,就可以拿到 value 值
    • 如果 current 是空值,其类型为 null ,不再继续访问 value,代码就不会报错了
const getValue = () => {
  // 正确:
  console.log(inputRef.current?.value);
  // 报错:未处理 current 属性类型为 null 的情况
  // console.log(inputRef.current.value)

技巧:在 JSX 中如何获取一个 DOM 对象的类型?鼠标移动到 JSX 元素上,就会显示出来该元素的类型

6. TS 类型-非空断言

目标:能够掌握 TS 中的非空断言的使用

  • 如果我们明确的知道对象的属性在使用时一定不为空,那么可以使用 TS 中提供的:非空断言
  • 非空断言!,从可能为空的类型中,去掉 null 和 undefined 类型
let x: null | undefined | number;
// t1 的类型为:null | undefined | number
let t1 = x;
// t2 的类型为:number
let t2 = x!;

应用场景:使用 ref 进行 DOM 操作时,可以将 ref 对象的 current 的类型 HTMLInputElement | null 中的 null 类型去掉变为:HTMLInputElemen 

const inputRef = useRef<HTMLInputElement>(null);
const getValue = () => {
  console.log(inputRef.current!.value);
  • 注意:使用非空断言时,一定要确保该属性不为空值,否则,即使类型不报错,将来在代码运行时也会报错!
let x: null | undefined | number = null;
// 错误演示:
// 类型不会报错,但是,代码运行时报错!因为 x 的值为 null
x!.toString();

7. TS 流程控制类型分析

目标:能够通过 if 判断来控制 TS 类型

  • TS 文档-流程控制分析
  • TS 可以通过 if 判断等操作来通过流程控制分析,来得到更加具体的类型,实现类型收缩(缩小类型的取值范围)
  • 这一检查机制也叫做:type guard - 类型守卫
    • 结果:变量在不同的位置,可以有不同的类型
let x: number | string;
if (typeof x === 'number') {
  // 鼠标放在 x 上查看类型为: number
  console.log(x);
} else {
  // 此时,x 的类型为: string
  console.log(x);

应用场景:使用 ref 进行 DOM 操作时,通过 if 判断来排除掉 null 类型 

const inputRef = useRef<HTMLInputElement>(null);
const getValue = () => {
  // 判断 inputRef.current 是否为空,如果是,直接 return 不再执行后面的代码
  if (!inputRef.current) return;
  // 如果此处代码执行,说明 inputRef.current 不为空,所以,此处可以直接访问 value 属性
  console.log(inputRef.current.value);

8. React 路由的使用

目标:能够在 TS 中使用 react 路由

  1. 安装路由:yarn add react-router-dom@5.3.0

  2. 安装路由的类型声明文件:yarn add @types/react-router-dom

  3. 在 pages 目录中,新建组件Home.tsxLogin.tsx(注意:组件的后缀为 .tsx

  4. 配置路由规则

核心代码

import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import Login from './pages/Login';
function App() {
  return (
    <Router>
      <div className="App">
            <Link to="/home">首页</Link>
            <Link to="/login">登录</Link>
        <Route path="/home" component={Home}></Route>
        <Route path="/login" component={Login}></Route>
    </Router>
export default App;

有了 TS 的支持后,代码提示变得非常的精确 

9. useHistory 的使用

目标:能够掌握 useHistory 在 TS 中的使用

  • useHistory hook 是一个泛型函数,接收一个类型变量来指定额外数据 state 的类型
  • useHistory hook 用来实现路由之间的跳转。根据跳转时是否携带额外数据,使用方式不同:

1.路由跳转不携带额外数据,用法与 JS 一样:

const history = useHistory();
const login = () => {
  history.push('/login');

2.路由跳转时携带额外数据,需要指定泛型类型:

  • 注意:泛型类型指定的是额外数据 state 的类型
// 调用 useHistory hook 时,为泛型函数指定额外数据 state 的类型:
const history = useHistory<{ from: string }>();
const login = () => {
  history.push('/login', {
    from: '/home/article',
  // 或者,传入对象参数:
  history.push({
    pathname: '/login',
    state: {
      from: '/home/article',

10. useLocation 的使用

目标:能够掌握 useLocation 在 TS 中的使用

  • useLocation hook 是一个泛型函数,接收一个类型变量来指定接收的 state 类型,与 useHistory 的泛型对应

  • useLocation hook 用来获取路由地址相关信息。根据是否要获取携带额外数据 state,使用方式不同:

1.不获取 state 数据:

const location = useLocation();

2.获取 state 数据: 

  • 注意:如果跳转路由时没有传递 state,state 的值为 undefined,所以,此处指定类型时也应该考虑到没有传递 state 时的类型
const location = useLocation<{ from: string } | undefined>();
// 因为 state 可能是 undefined 类型,所以,此处通过 ?. 来访问 from
console.log(location.state?.from);

注意:因为 Home 和 Login 都需要指定额外数据 state 的类型,因此可以将类型存放到类型声明文件中,实现类型复用: 

// types.d.ts
export type LoginState = { from: string } | undefined;
// Login.tsx 中:
// import type ... 表示:专门用来导入类型的语法
// 此处,使用 import 导入类型时,可以省略 type 也可以带着 type
import type { LoginState } from './types';
const location = useLocation<LoginState>();
// Home.tsx 中:
import type { LoginState } from './types';
const history = useHistory<LoginState>();

11. useParams 的使用

目标:能够掌握 useParams 在 TS 中的使用

  • useParams hook 是一个泛型函数,接收一个类型变量来指定 params 对象的类型
  • 根据配置路由规则时,路由参数是否可选,使用方式不同:

1.路由参数必选

<Route path="/home/publish/:id" />;
// 因为路由规则中要求参数一定存在,所以,此处不需要考虑不存在的情况
const params = useParams<{ id: string }>();
console.log(params.id);

2.路由参数可选

<Route path="/home/publish/:id?" />;
// 因为路由规则中参数是可选的,所以,此处需要考虑 id 不传的情况,让 id 变为可选属性
const params = useParams<{ id?: string }>();
console.log(params.id);

12. TS 类型-unknown 类型

目标:能够知道 TS 中的 unknown 类型

  • unknown 类型是类型安全的 any

  • 可以把任何类型的值赋值给 unknown 类型的变量(可以接口任意类型的数据)

  • 在使用 unknown 类型前,必须先将其设置为一个具体的类型,否则,无法对其进行任何操作

对比 any 和 unknown 类型:

1.对于 any 类型来说,TS 不会对其进行类型检查

// 可以进行任意操作,没有安全可言
let value: any;
value = true;
value = 1;
value.length;

 2.unknown 类型

let value: unknown;
value = 'abc'(
  // 先转化为具体类型再使用
  value as string,
).length;
// 先判断是 string 类型,再使用
if (typeof value === 'string') {
  value.length;

12. never 类型和 unknown 类型

  • never 处理 TS 类型系统的最底层
    • 无法将任意类型的数据赋值给 never 类型
    • 可以将 never 类型赋值给任意其他类型
    • 理解:never 表示啥也不是,所以,无法给 never 设置任何内容
    • 理解:never 处于最底层,相当于任何类型的子类型,所以,可以赋值给其他任何类型
      • 比如,'a' 字面量就是 string 的子类型 let s: string = 'a'
  • unknown 处于 TS 类型系统的最顶层
    • 可以将任意类型的数据赋值给 unknown 类型
    • 无法将 unknown 类型赋值给任意其他类型
    • 简单来说:unknown 类型可以接受任意类型,但是无法赋值给其他类型
    • 理解:unknown 表示不确定,不确定就可以表示任意类型,既然可以是任意类型,所以可以接受任意类型的数据
    • 理解:unknown 表示不确定,不确定就可以表示任意类型,既然可以是任意类型,所以就无法赋值给一个特点的类型

// 头部 底部 unknown -> ... -> ...-> never unknown 可以按照 “万物皆对象”
的方式来理解:“万物皆 unknown” 

let u: unknown;
// 可以将任意类型的数据赋值给 unknown 类型
u = 1;
u = 'a';
// 错误演示:
// let a: number = u
写在前面: 首先,什么是TypeScript? 官方原话:TypeScript is a typed superset of JavaScript that complies to plain JavaScript. Any host. Any OS. Open source. TypeScriptJavaScript类型的超集(强类型版本),它可以编译成纯JavaScript,它可以再任何浏览器,任何计算机和任何操作系统上运行,并且开源。 嗯,是的,你可以理解为TypeScript硬是把JavaScript(弱类型语言)"掰弯"了,变成强类型语言;强类语言的优势在于静态类型的检查,TypeScript虽然是强类型的语言,但是如果对象被声明为any类型, 使用TypeScript的主要工作是在组件定义prop和state的类型。将项目的.js文件扩展名更改为.ts或.tsx。如果你使用的是create-react-app,它会自动将文件扩展名更改为.tsx。在组件使用TypeScript。 在交互式监视模式下启动测试运行器。 有关更多信息,请参见关于的部分。 npm run build 构建生产到应用程序build文件夹。 它在生产模式下正确捆绑了React,并优化了构建以获得最佳性能。 生成被最小化,并且文件名包括哈希值。 您的应用已准备好进行部署! 有关更多信息,请参见关于的部分。 npm run eject 注意:这是单向操作。 eject ,您将无法返回! 如果您对构建工具和配置选择不满意,则可以随时eject 。 此命令将从您的项目删除单个生成依赖项 在交互式监视模式下启动测试运行程序。 有关更多信息,请参见关于的部分。 npm run build 构建生产到应用程序build文件夹。 它在生产模式下正确捆绑了React,并优化了构建以获得最佳性能。 最小化构建,文件名包含哈希。 您的应用已准备好进行部署! 有关更多信息,请参见有关的部分。 npm run eject 注意:这是单向操作。 eject ,您将无法返回! 如果您对构建工具和配置选择不满意,则可以随时eject 。 此命令将从项目删除单个构建依赖项。 而是将所有配置文件和传递依赖项(webpack,Babel,E 大厂技术高级前端Node进阶点击上方程序员成长指北,关注公众号回复1,加入高级Node交流群工作用的技术栈主要是React hooks + TypeScript使用三月有余,其... typescript1、typescript介绍2、特点3、 说起typescript你是不想到了javascript呢,没错,它们确实是有关系的,具体是什么,往下看! 1、typescript介绍 学了这么久的javascript,相信你已经知道了javascript是一门弱类型语言。 强类型语言就是声明变量的同时限制数据类型,而弱类型语言则相反,对于数据类型的限制并不那么严格。 比如你定义了一个变量,但是赋值的时候可以赋任何类型的数据,而强类型就比较严格了,是什么类型就必须严格匹配。 typescrip 转自https://typescript.bootcss.com/tutorials/react.html 这篇快速上手指南会教你如何将TypeScriptReact结合起来使用。 在最后,你将学到: 使用TypeScriptReact创建工程 使用TSLint进行代码检查 使用Jest和Enzyme进行测试,以及 使用Redux管理状态 我们会使用create-react-app工... react项目构建可以很简单,但是如果是结合typescript,其实也不是很麻烦,官网也有很明确的说明。有两种办法: 1、直接构建带有typescriptreact项目,我们需要增加额外的参数,模版不能使用默认的cra-template。而是使用cra-template-typescript。 npx create-react-app tsreactdemo --template typescript 最早,我们创建typescriptreact项目命令好像直接就是np... 本教程不用react-script这种工具,用的webpack + eslint(可选) + prettier(可选) + babel,使用编辑器用的vscode。 以下会涉及到ts语法和redux、react-router-dom的一些技巧,也是入门时学习到的。 depend # babel yarn add @babel/core @babel/preset-reac @babel/preset-typescript @babel/preset-env -D # webpack 泛型是TypeScript的一个重要部分:它们看起来很奇怪,它们的目的不明显,而且它们可能很难分析。本文旨在帮助你理解和揭开TypeScript泛型的神秘面纱,特别是它们在React的应用。 Typescript一、关于Typescript1.什么是Typescript?2.安装 TypeScript二、在 react 使用 ts 需要注意几点三、ts在react使用推荐阅读 一、关于Typescript TypeScriptJavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持。 它的第一个版本发布于 2012 年 10 月,经历了多次更新后,现在已成为前端社区不可忽视的力量,不仅在 Microsoft 内部得到广泛运用,而且 Google 开发的 Angula