Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.0k views
in Technique[技术] by (71.8m points)

typescript - Redefined parameter loses its inferred type when in another block

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.

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.

"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.

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!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...