首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
开篇:用正确的方式学习 TypeScript
打造 TypeScript 的开发环境
TypeScript中的原始类型与对象类型
TypeScript中的字面量类型与枚举
TypeScript中的函数重载与面向对象
TypeScript的内置类型:any、unknown、never 与类型断言
TypeScript 类型工具
TypeScript 中无处不在的泛型
TypeScript 类型系统层级:从 Top Type 到 Bottom Type
TypeScript 类型里的逻辑运算:条件类型与 infer
TypeScript 中的内置工具类型基础
TypeScript 反方向类型推导:用好上下文相关类型
TypeScript 函数类型:协变与逆变的比较
TypeScript中类型编程与类型体操的意义
TypeScript模板字符串类型
TypeScript模板字符串工具类型进阶
TypeScript类型声明、类型指令与命名空间
在 React 中愉快地使用 TypeScript:内置类型与泛型坑位
让 ESLint 来约束你的 TypeScript 代码:配置与规则集介绍
TypeScript装饰器与反射元数据
TypeScript控制反转与依赖注入
TSConfig 全解(上):构建相关配置
TSConfig 全解(下):检查相关、工程相关配置
当前位置:
首页>>
技术小册>>
TypeScript入门指南
小册名称:TypeScript入门指南
React 和 TypeScript 都是非常流行的技术,在组合使用时能够大大提高代码的可靠性和可维护性。TypeScript 的强类型检查能够帮助我们在编写 React 应用时更早地发现问题,而 React 的声明式编程模型则让我们能够更加专注于 UI 的实现。 本章节将介绍在 React 中愉快地使用 TypeScript 的一些技巧和注意事项,包括内置类型和泛型的使用,同时也会通过一些代码示例来说明。 ------------------------------- **1、内置类型** **React.FC** React.FC 是 React 中的一个内置类型,它表示一个 React 函数组件。使用 React.FC 可以为函数组件的 Props 添加类型注解,从而让 TypeScript 在编译时对 Props 进行类型检查。 下面是一个使用 React.FC 的示例: ```javascript import React from 'react'; interface Props { name: string; } const Greeting: React.FC<Props> = ({ name }) => { return <div>Hello, {name}!</div>; }; export default Greeting; ``` 在上面的代码中,我们首先定义了一个 Props 接口,它包含一个名为 name 的属性,类型为 string。然后使用 React.FC<Props> 来定义 Greeting 组件的类型,指定 Props 的类型为 Props。最后,我们实现了 Greeting 组件,并将其导出。 在这个示例中,我们使用了解构赋值来从 Props 中获取 name 属性,并在组件中使用它。如果我们尝试将 Props 中的 name 属性的类型改为 number,TypeScript 就会在编译时报错,提示我们该属性的类型不正确。 **React.ReactNode** React.ReactNode 是另一个内置类型,它表示一个 React 组件的子元素。使用 React.ReactNode 可以为组件的子元素添加类型注解,从而让 TypeScript 在编译时对子元素进行类型检查。 下面是一个使用 React.ReactNode 的示例: ```javascript import React from 'react'; interface Props { children: React.ReactNode; } const Box: React.FC<Props> = ({ children }) => { return <div style={{ border: '1px solid black' }}>{children}</div>; }; export default Box; ``` 在上面的代码中,我们定义了一个 Props 接口,它包含一个名为 children 的属性,类型为 React.ReactNode。然后使用 React.FC<Props> 来定义 Box 组件的类型,指定 Props 的类型为 Props。最后,我们实现了 Box 组件,并将其导出。 在这个示例中,我们使用了 Props 中的 children 属性来渲染组件的子元素。由于我们将 children 的类型注解为 React.ReactNode,因此如果我们尝试将一个不是 React 组件的元素传递给 Box 组件作为子元素,TypeScript 就会在编译时报错。 **2、泛型** 泛型是 TypeScript 中非常强大的一种特性,它可以让我们编写更加通用的代码。在 React 中,我们可以使用泛型来创建更加灵活的组件和函数,从而提高代码的复用性和可读性。 **泛型组件** 下面是一个使用泛型创建通用表单组件的示例: ```javascript import React, { useState } from 'react'; interface FieldProps<T> { value: T; onChange: (value: T) => void; } interface Props<T> { fields: Array<{ name: string; label: string } & FieldProps<T>>; } function Form<T>({ fields }: Props<T>) { const [values, setValues] = useState<T>(() => { const initial: Partial<T> = {}; fields.forEach((field) => (initial[field.name] = field.value)); return initial as T; }); function handleChange(name: string, value: T) { setValues((prev) => ({ ...prev, [name]: value })); } function handleSubmit(event: React.FormEvent) { event.preventDefault(); console.log(values); } return ( <form onSubmit={handleSubmit}> {fields.map((field) => ( <div key={field.name}> <label htmlFor={field.name}>{field.label}</label> <input type="text" id={field.name} value={values[field.name]} onChange={(event) => handleChange(field.name, event.target.value as T) } /> </div> ))} <button type="submit">Submit</button> </form> ); } export default Form; ``` 在上面的代码中,我们定义了一个 FieldProps 接口,它包含一个 value 属性和一个 onChange 方法,用于表示表单控件的值和值变化的回调函数。然后定义了一个 Props 接口,它包含一个名为 fields 的属性,类型为 FieldProps<T> 的数组。最后我们实现了 Form 组件,使用泛型来表示表单的值的类型。 在 Form 组件中,我们使用 useState 钩子来管理表单的值。在 handleChange 函数中,我们使用 setValues 方法来更新表单的值,而 handleSubmit 函数则用于处理表单的提交。 使用上面的 Form 组件,我们可以创建一个包含多个输入框的表单,如下所示: ```javascript import React from 'react'; import Form from './Form'; interface User { name: string; age: number; } function App() { return ( <div> <Form<User> fields={[ { name: 'name', label: 'Name', value: '', onChange: (value: string) => console.log(value), }, { name: 'age', label: 'Age', value: 0, onChange: (value: number) => console.log(value), }, ]} /> </div> ); } export default App; ``` 在上面的代码中,我们将 User 类型作为泛型参数传递给 Form 组件,同时为每个输入框传递一个包含 value 和 onChange 属性的对象。 **泛型函数** 下面是一个使用泛型创建通用的 map 函数的示例: ```javascript function map<T, U>(array: T[], callback: (item: T) => U): U[] { const result: U[] = []; for (let i = 0; i < array.length; i++) { result.push(callback(array[i])); } return result; } export default map; ``` ```javascript 在上面的代码中,我们定义了一个 map 函数,它使用泛型来表示输入数组的类型和输出数组的类型。map 函数接收两个参数:一个数组和一个回调函数,回调函数接收一个数组元素作为参数,并返回一个新的元素。map 函数遍历输入数组,对每个元素应用回调函数,将结果添加到一个新的数组中,最后返回这个数组。 使用上面的 map 函数,我们可以轻松地创建一个新的数组: ```tsx import React from 'react'; import map from './map'; function App() { const numbers = [1, 2, 3, 4, 5]; const doubled = map(numbers, (n) => n * 2); return ( <div> <p>Original numbers: {numbers.join(', ')}</p> <p>Doubled numbers: {doubled.join(', ')}</p> </div> ); } export default App; ``` 在上面的代码中,我们创建了一个包含 1 到 5 的数字的数组,并使用 map 函数将数组中的每个数字翻倍。最后,我们在页面上显示了原始数字和翻倍后的数字。 **3、坑位** 虽然使用 TypeScript 和泛型可以帮助我们编写更加安全和健壮的代码,但是在使用时还是需要注意一些坑位,下面是一些需要注意的问题: **类型推断** 在 TypeScript 中,类型推断是非常重要的。在编写泛型代码时,如果不小心定义了错误的类型,可能会导致类型推断出现问题。例如,下面的代码: ```javascript function identity<T>(arg: T): T { return arg; } const result = identity('hello'); console.log(result.length); ``` 在上面的代码中,我们定义了一个 identity 函数,它使用泛型来表示输入和输出的类型。然后我们调用这个函数,并将一个字符串作为参数传递给它。最后,我们尝试在控制台上打印函数返回值的 length 属性。然而,TypeScript 编译器并没有报错,而是将 result 推断为 string 类型,因此在访问 length 属性时不会出现错误。 为了避免这种情况发生,我们可以显式指定泛型类型,如下所示: ```javascript const result = identity<string>('hello'); ``` **类型限制** 在使用泛型时,需要注意泛型类型的限制。例如,下面的代码: ```javascript interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); return arg; } loggingIdentity(3); // error: number does not have a 'length' property ``` 在上面的代码中,我们定义了一个接口 Lengthwise,它包含一个 length 属性。然后我们定义了一个 loggingIdentity 函数,它使用泛型 T,并限制泛型 T必须具有 length 属性,以便我们可以打印出这个属性的值。最后,我们尝试调用 loggingIdentity 函数,并将一个数字作为参数传递给它。由于数字类型没有 length 属性,TypeScript 编译器会报错。 在使用泛型时,我们需要仔细考虑泛型类型的限制,以确保函数不会收到无效的参数。 **类型重载** 在 TypeScript 中,我们可以使用类型重载来定义多个函数签名,以处理不同类型的参数。例如,下面的代码: ```javascript function reverse<T>(arg: T[]): T[]; function reverse<T>(arg: T): T; function reverse(arg: any) { if (Array.isArray(arg)) { return arg.reverse(); } else { return arg.split('').reverse().join(''); } } console.log(reverse([1, 2, 3, 4, 5])); // [5, 4, 3, 2, 1] console.log(reverse('hello')); // 'olleh' ``` 在上面的代码中,我们定义了两个函数签名来处理数组和字符串类型的参数。然后我们定义了一个 reverse 函数,并使用类型重载来定义两个函数签名。第一个函数签名接收一个数组,并返回一个数组。第二个函数签名接收一个字符串,并返回一个字符串。最后,我们在控制台上分别调用了这两个函数。 使用类型重载可以帮助我们更好地处理不同类型的参数,并提高代码的可读性。 **小结** 在 React 中使用 TypeScript 和泛型可以帮助我们编写更加安全和健壮的代码。通过使用类型限制、类型推断和类型重载等技术,我们可以避免很多常见的编程错误,并提高代码的可维护性和可读性。如果你是一名 React 开发者,并且想要提高自己的编程技能,那么学习 TypeScript 和泛型是非常重要的一步。
上一篇:
TypeScript类型声明、类型指令与命名空间
下一篇:
让 ESLint 来约束你的 TypeScript 代码:配置与规则集介绍
该分类下的相关小册推荐:
TypeScript 全面进阶指南
TypeScript开发实战
剑指TypeScript