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

相关推荐
zeijiershuai2 分钟前
Vue框架
前端·javascript·vue.js
写完这行代码打球去4 分钟前
没有与此调用匹配的重载
前端·javascript·vue.js
华科云商xiao徐4 分钟前
使用CPR库编写的爬虫程序
前端
狂炫一碗大米饭6 分钟前
Event Loop事件循环机制,那是什么事件?又是怎么循环呢?
前端·javascript·面试
IT、木易8 分钟前
大白话Vue Router 中路由守卫(全局守卫、路由独享守卫、组件内守卫)的种类及应用场景
前端·javascript·vue.js
顾林海9 分钟前
JavaScript 变量与常量全面解析
前端·javascript
程序员小续9 分钟前
React 组件库:跨版本兼容的解决方案!
前端·react.js·面试
乐坏小陈10 分钟前
2025 年你希望用到的现代 JavaScript 模式 【转载】
前端·javascript
生在地上要上天10 分钟前
从600行"状态地狱"到可维护策略模式:一次列表操作限制重构实践
前端
oil欧哟12 分钟前
🥳 做了三个月的学习卡盒小程序,开源了!
前端·vue.js·微信小程序