我试图理解为什么Typescript无法正确获取内部函数内部的对象属性参数的类型(该参数可以是未定义的),但当同一属性被分配给外部函数范围中的自己的变量时,缩小就会无缝发生.

我用这个片段来重现这个问题:

type MyType = {
    optional?: string
}

(arr: string[], param: MyType) => {

    if (param.optional) {
        const includes = arr.includes(param.optional)  // <-- Fine

        arr.filter(function (item) {
            return item.includes(param.optional)  // <-- Wrong! Type undefined is not assignable...
        })
    }
}

在if分支中,Typescript警告我在过滤器内部函数中使用param.optional,因为它可能是string | undefined,无论当它在arr.includes(param.optional)中使用时,根本没有任何警告.

这对我来说似乎很奇怪,因为如果我不使用param.optional,而是将相同的值赋给它自己的变量Typescript,就能够完美地缩小其类型(string).

type MyType = {
    optional?: string
}

(arr: string[], param: MyType) => {
    const variable = param.optional

    if (variable) {
        const includes = arr.includes(variable)  // <-- Fine

        arr.filter(function (item) {
            return item.includes(variable)  // <-- Fine
        })
    }
}

为什么会发生这种行为?它与对象本身有什么关系(因为如果参数只是原始可选值string | undefined,这个问题就不会发生)?

推荐答案

因为在一般情况下这样做是不安全的.

TypScript不知道filter的作用,因此它不知道何时调用其回调(现在同步,或以后同步),因此不知道对象是否被函数范围外的其他代码更改.函数外部代码的更改可能会使类型保护无效.

但对于您的(命名有趣的)variable常数,TypScript知道值can't发生了变化,因此可以应用类型保护.如果您使用let而不是const,它甚至可以工作,因为TypScript可以看到没有对variable的任何分配.(但如果您在filter调用后使用let and添加variable = undefined;,您会得到与param.optional相同的错误,因为同样,TypScript不知道回调的代码何时相对于该分配运行:example.)

Typescript相关问答推荐

如何使用Generics保留构造函数的类型信息?

防止获取发出不需要的请求

使用带有RxJS主题的服务在Angular中的组件之间传递数据

使某些类型的字段变为可选字段'

我们过go 不能从TypeScript中的联合中同时访问所有属性?

泛型和数组:为什么我最终使用了`泛型T []`而不是`泛型T []`?<><>

TypeScript Page Routing在单击时不呈现子页面(React Router v6)

如何将联合文字类型限制为文字类型之一

对数组或REST参数中的多个函数的S参数进行类型判断

如何将定义模型(在Vue 3.4中)用于输入以外的其他用途

为什么我的查询钩子返回的结果与浏览器的网络选项卡中看到的结果不同?

类型脚本可以推断哪个类型作为参数传递到联合类型中吗?

按函数名的类型安全类型脚本方法包装帮助器

如何合并两个泛型对象并获得完整的类型安全结果?

如何过滤文字中的类对象联合类型?

如何将对象数组中的键映射到另一种对象类型的键?

在打字脚本中对可迭代对象进行可变压缩

字符串文字联合的分布式条件类型

如何使用 runInInjectionContext 中的参数测试功能性路由防护

从 npm 切换到 pnpm 后出现Typescript 错误