【问题标题】:Using optional chaining and array.length invalidates typescript narrowing使用可选链接和 array.length 会使打字稿缩小无效
【发布时间】:2022-12-22 14:47:10
【问题描述】:

我只是注意到,如果我在缩小类型时使用 length 属性,打字稿不知道变量不为空:

declare const foo: { method: () => void, groups: number[] } | undefined;

if (foo?.groups.length > 0) {
    foo.method();
}

这给你一个错误,说这个对象可能是未定义的。如果您删除长度检查,那么它会按预期工作。 这是TS限制吗?预期的行为?不好的做法?

playground link

【问题讨论】:

  • 这段代码无论如何都有类型错误,因为foo?.groups.length可以是undefined,所以它不一定能与0相提并论。通常,Typescript 仅在条件具有几种特定形式之一时才进行类型缩小,详细信息参见此处的文档:typescriptlang.org/docs/handbook/2/narrowing.html
  • 数组上的长度如何未定义? groups 属性不是可选的,因此只要它不是未定义的并且它是预期的对象,groups 就是一个数组
  • 根本不一定有数组。如果 foo 未定义,表达式 foo?.groups.length 将被计算为 undefined。当然,只要它不是 undefined 那么结果就不是 undefined,但是如果它undefined 那么它将是 undefined ...
  • 那不是问题。 Undefined 不大于 0,因此它求值为 true 的唯一机会是 length 是一个大于 0 的数字,此时 foo 已定义。
  • 是的,undefined 与 Javascript 中的 0 相当,但在 Typescript 中这是类型错误,因为程序员实际上通常不想比较 undefined 以查看它是大于还是小于数字。该错误与类型缩小无关,只是您使用可能未定义的值与数字进行比较。如果你写let a = 5 + foo?.groups.length;,你会得到类似的错误,因为是的,Javascript 允许你做5 + undefined,但 Typescript 的工作是告诉你,如果你的代码可以做到这一点,那可能是一个错误。

标签: typescript


【解决方案1】:

在你的情况下,如果fooundefinedgroups自动是undefined。你不能将 undefined 与打字稿中带有 > 运算符的数字进行比较,因为这是两种不同的、无法比较的类型。

在访问groups.length 之前,您应该使用类型保护来确保foo 不是undefined

这是我如何在我的用例中执行此操作的示例:

type Props = {
  post: {
    tags: string[]
  } | undefined
}
const SinglePost = ({ post }: Props) => {
  // this type guard ensures post is not undefined
  if (!post) return <H1>Not found</H1>
  return (
    ...
      // then you can access length of an underlying array without type errors
      {post.tags.length > 0 && <div>something</div>}
    ...
  )
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-25
    • 2020-05-22
    • 2018-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多