重新定义的参数在另一个块中丢失其推断类型 [英] Redefined parameter loses its inferred type when in another block

查看:16
本文介绍了重新定义的参数在另一个块中丢失其推断类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

例如,我将使用一个函数,该函数接收一个参数并返回一个始终返回一个数字的函数.我将有两种可能的结果:

As example, I'll use a function that receive a argument and returns a function that always returns a number. I'll have two possible results:

  • 如果我在第一个块中转换参数,返回类型将丢失

  • if I convert the argument in the first block, the return type will get lost

// foo(bar: string | number) => () => string | number

function foo(bar: string | number) {
    bar = +bar;

    return function () {
        return bar;
    }
}

  • 如果我在第二个块中转换参数,返回类型将正确推断:

  • if I convert the argument in the second block, the return type will be inferred properly:

    // foo2(bar2: string | number) => () => number
    
    function foo2(bar2: string | number) {
        return function () {
            return +bar2;
        }
    }
    

  • 为什么重定义的参数类型会丢失?

    Why does the type of a redefined parameter get lost?

    推荐答案

    TypeScript 编译器使用 基于控制流的类型分析 以推断更窄的变量类型.正如您所注意到的,当您使用 bar: string |number 并设置为+barbar 的值肯定会是一个number.对于范围的其余部分,除非您再次重新定义 bar,否则 TypeScript 将知道 bar 是一个 number.

    The TypeScript compiler uses control flow based type analysis to infer narrower types of variables. As you note, when you take bar: string | number and set it to +bar, the value of bar will definitely be a number immediately afterward. For the remainder of the scope, unless you redefine bar again, TypeScript will know that bar is a number.

    除非没有.返回匿名函数 function(){return bar;} 引入了 闭包,其中 bar 的值将无限期地保持未经检查,直到调用返回的函数为止.此时,TypeScript 编译器放弃了.它不知道是否有人会在调用该函数之前将 bar 的值更改为 string,因此它不会将缩小的类型保留在 clousre 中.

    Except when it doesn't. Returning the anonymous function function(){return bar;} introduces a closure where the value of bar will remain unexamined indefinitely until such time as that returned function is called. At this point, the TypeScript compiler gives up. It doesn't know if someone will change the value of bar to a string before that function is called, so it doesn't keep the narrowed type within the clousre.

    等等",你可能会说,通过检查我可以看到在我返回那个函数之后 bar 的值不会发生任何变化,所以它总是一个 数字 永远."你可能是对的.不幸的是,编译器没有你那么聪明,遇到闭包时放弃只是用于使控制流分析问题易于处理的众多启发式方法之一.

    "Wait", you might say, "by inspection I can see that nothing can happen to the value of bar after I return that function, so it's always a number forever." And you're probably right. Unfortunately the compiler is not as smart as you, and giving up when encountering a closure is just one of many heuristics used to keep the problem of control-flow analysis tractable.

    在 GitHub 上有一个关于正确"控制流分析的困难的很好的问题:Microsoft/TypeScript #9998:控制流分析中的权衡.在很多情况下,编译器可能会被愚弄,要么未能缩小类型(不完整),要么过度缩小类型(不健全).事情就是这样,至少在我们达到技术奇点之前.

    There is an excellent issue in GitHub about the difficulty with getting control-flow anlaysis "right": Microsoft/TypeScript #9998: Trade-offs in Control Flow Analysis. There are many cases where the compiler can be fooled into either failing to narrow a type (incompleteness) or over-narrowing a type (unsoundness). That's just the way it is, at least until we reach the technological singularity.

    希望有所帮助;祝你好运!

    Hope that helps; good luck!

    这篇关于重新定义的参数在另一个块中丢失其推断类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆