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的类型,但是不会打破组件的可组合性 😉

相关推荐
2402_83970805几秒前
第十章:作业
开发语言·前端·javascript
诗水人间3 分钟前
前后端分离,解决vue+axios跨域和proxyTable不生效等问题
前端·javascript·vue.js·springboot·springsecurity·跨域·cros
恩爸编程4 分钟前
纯前端js完成游戏吃豆人
前端·javascript·游戏·游戏程序·开源软件·游戏策划·游戏机
粉03214 分钟前
用web前端写出一个高校官网
前端·css
@大迁世界4 分钟前
停止在 React 组件回调中使用箭头函数!
前端·javascript·react.js·前端框架·ecmascript
焦糖酒6 分钟前
JS精进之Hoisting(提升)
开发语言·前端·javascript
像素之间8 分钟前
`URL.createObjectURL(blob)` 和 `URL` 对象的区别
前端·javascript·网络
( •̀∀•́ )92018 分钟前
如何使用 `global.json` 管理(切换) .NET SDK 版本
前端·json·.net
小彭努力中28 分钟前
141. Sprite标签(Canvas作为贴图)
前端·深度学习·3d·webgl·three.js
遇到困难睡大觉哈哈41 分钟前
JavaScript中的箭头函数以及编写优化
前端·javascript·vue.js