TS系列(1): React中能否使子组件实现“类型安全”?

本篇是**「一起学习** TypeScript **」**系列的开篇之作,接下来笔者将持续深耕,不定时更新一系列精彩纷呈的TypeScript文章,旨在解答使用TypeScript过程中的各种疑难杂症,一起探索TS的无穷魅力!

一、引言

在进入正题之前,我们先来明确一个概念,什么是"类型安全"(Type Safety)?

看看ChatGPT怎么回答这个问题:

"Type safety"(类型安全)是指编程语言的一个特性,它确保在编译时或运行时,程序中的类型匹配是正确的。这意味着程序员不能将一个类型不匹配的值赋给一个变量,或者将一个类型不匹配的参数传递给一个函数。这可以避免许多常见的编程错误,例如将字符串传递给一个期望整数的函数,或者将一个浮点数赋给一个期望布尔值的变量。类型安全还可以提高程序的可读性和可维护性,因为它使得程序员更容易理解代码中的数据类型和操作。

一句话总结下:类型安全是指确保数据在使用时保持预期的类型。

二、可以实现子组件 "类型安全"么?

如果你已经使用过TS和JSX一段时间,也许你会面临一种情形:想要将一个组件的子组件限制为某种特定的类型。

那么,这个述求能否实现呢?🤔

先来看一个简单的例子🌰:现在有一个Select组件,它的子组件为Option。如果想确保Option是唯一能够传递给Select的组件👇🏻

javascript 复制代码
//✅
<Select>
  <Option value="1">One</Option>
  <Option value="2">Two</Option>
  <Option value="3">Three</Option>
</Select>

//❌
<Select>
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
</Select>

看起来似乎有很多选择:使用ReactElement,或者ReactNode,或者ReactChild?

实际上,这些类型都没有任何效果,你不能告诉 TypeScript"只使用指定类型的组件作为子组件"!

组件总是JSX.Element类型

根本原因在于 TypeScript 解释 JSX 的方式:不管是什么组件,组件里面有什么 props TS 看到一个JSX语句时,总是把它定义为一个 JSX.Element

当我们想让Select组件仅接收Option组件作为参数时,我们也许会这么写:

ini 复制代码
type SelectProps = {
   children: ReactElement<OptionProps>[];
}

但是,实际上,Option组件还是会返回一个JSX.Element !🤯

尝试手动覆盖返回类型

那么,如果我们使用TS的as语法覆盖组件的返回类型呢?

下面的代码👇🏻中,你会发现element的类型依然是React.JSX.Element!😒

不过,如果你手动调用Option() ,确实会达到想要的效果:

这种手动调用的方式其实是绕过了JSX解释的机制,所以TS能够理解Option要返回的是我们指定的字符串。

但是需要注意的是,在React中手动调用Option()是一个糟糕的主意------它会打破React对代码所做的各种假设,将会导致一些不可预计的错误。-_-||

三、结论

综上所述: TypeScript 中不可能将 React 组件的子组件限制为某种类型

但是,这里仍然有一件事情需要思考:你是真的想要限制子组件类型吗?😏

React的魔力本质上是在于你可以按照你喜欢的任何方式组合你的组件。但是如果你限制了子组件为一种固定的类型,你将打破这种可组合性(composability)

一种更好的方式是:也许你可以通过使用对子组件的props进行限制来实现你的目的👇🏻

ini 复制代码
<Select
  options={[
    { value: "1", label: "One" },
    { value: "2", label: "Two" },
    { value: "3", label: "Three" },
  ]}
/>

使用上面这种方式,你仍然可以限制children的类型,但是不会打破组件的可组合性 😉

相关推荐
正小安31 分钟前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光2 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   2 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   2 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常2 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇3 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr3 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho4 小时前
【TypeScript】知识点梳理(三)
前端·typescript