是否可以在父组件到达使用相同 prop 的子组件之前在父组件中断言 prop 的类型

Is it possible to assert a prop's type in parent component before it reaches children that use the same prop

提问人:23k 提问时间:11/16/2023 更新时间:11/24/2023 访问量:116

问:

赏金将在 2 天后到期。这个问题的答案有资格获得 +300 声望赏金。23k希望引起人们对这个问题的更多关注

我有一个组件,它仅在给定条件为真时才呈现子项。否则,它会呈现一个通用的回退组件,以尝试避免在我们的代码库中很常见的东西上出现一些冗余。NotFoundGuard

我正在尝试找出是否可以断言到 TypeScript,而不是在它到达子组件时productnull

<NotFound if={product != null}>
  <ProductDisplay product={product} />     <- Type 'Product | null' not assignable to type 'Product'
</NotFound>

该组件大致如下所示NotFound

type Props = { if: boolean };

function NotFound(prop: Props): ReactNode {
  if (!props.if) {
    return children;
  }

  return <Fallback />;
}

我想避免与操作员断言。更新组件以采用渲染道具可能会正常工作,但我对“类型魔术”更感兴趣,即使它有点笨拙。!

我的尝试看起来像这样,不出所料没有奏效。

type Props = { if: boolean };

function dummyAssert(cond: boolean): asserts cond is true {}

function NotFound(prop: Props): ReactNode {
  if (!props.if) {
    dummyAssert(props.if);
    return children;
  }

  return <Fallback />;
}

在这种情况下,是否有可能让类型提示正常工作?

<NotFound if={product != null}>
  <ProductDisplay product={product} /> // No type error here about potential null prop
</NotFound>
ReactJS TypeScript 类型

评论

0赞 SoZettaSho 11/24/2023
一个条件语句(如果是第三级),其分支不是......已经断言到 Typescript 不是 .你让这比现在困难得多。productnullproductnull

答:

4赞 tao 11/19/2023 #1

就我个人而言,我会完全放弃并简化为:<NotFound />

{
  product === null ? <Fallback /> : <ProductDisplay product={product} />
}

但是,让我们把它放在一边——并保留(假装它有更多的业务逻辑,或者我们不想将这个逻辑暴露/重复到包含)的组件中——恕我直言,正确的解决方案非空断言运算符:<NotFound /><NotFound />

<NotFound if={product !== null}>
  <ProductDisplay product={product!} />
</NotFound>

为什么?

问题的关键在于,TS 不知道在类型方面有什么作用。
因此,我们必须在父组件中以 TS 理解的方式告知它我们的自定义逻辑(包含在指令中)。这意味着使用非 null 运算符的替代方法是
ifif

<NotFound if={product !== null}>
  {
    product !== null && <ProductDisplay product={product} />
  }
</NotFound>

在我看来,这更糟(我们必须重复 JSX 标记内部的内容)。if


现在让我们退后一步,问问自己:“什么是非空断言运算符?它为什么存在,什么时候应该使用?
它适用于 TS 无法正确确定表达式的可为 null 性的情况。在这种情况下,我们绝对肯定地知道不能传递 ,但 TS 无法确定这一点。1
productnull<ProductDisplay />

因此,非空断言运算符在这里不是错误/黑客/扫荡,而是正确的解决方案。它正是为像我们这样的情况开发的,我们应该使用它。阿拉伯数字

用你自己的话来说,这就是你一直在寻找的“类型魔力”。


1 - 如果你好奇为什么 TS 无法了解指令的作用,那是因为 TS 无法深入了解 React 如何解释 JSX 以创建 DOM 元素,以及这些 DOM 元素之间的关系是什么,一旦创建。简而言之,TS 不知道在 React 组件的上下文中代表什么。
2 - 非 null 运算符的错误用法是禁止有效警告(在本例中,如果传递的可能性实际存在)。
ifchildrenproductnull<ProductDisplay />