TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Improve binding element type inference using `CheckMode`

Open babakks opened this issue 3 years ago • 0 comments

Fixes #49989 Alternative to PR #50241.

Here, to prevent false circular-relationship on binding elements initialized with their siblings (like the code segment below), we've utilized CheckMode values other than Normal as an indicator of suppressing type-checking errors.

const [a, b = a] = [0];
// or
const [a, b = a + 1] = [0];

~One gotcha in this PR was to revert the updated links (i.e., links.type) of a symbol. Because once a circular relationship error was encountered the type of the symbol is inferred to be any and then somewhere in the call stack, the symbol's associated links.type would be assigned to that returned any type. So, in cases other than CheckMode.Normal we'd replace back the links.type old value.~ (Sorry, that was not up-to-date)

The gotcha is that I had to suppress updating the symbol's links.type (to any type) for other than CheckMode.Normal cases, because that would block further efforts to find the correct type for the symbol. Now, I'm thinking maybe it's better to also check if the returned type is any and then do the suppression. I didn't find any better approach than this, so let me know if there's one:

function getTypeOfVariableOrParameterOrProperty(symbol: Symbol, checkMode?: CheckMode): Type {
    const links = getSymbolLinks(symbol);
    let result = links.type;
    if (!result) {
        result = getTypeOfVariableOrParameterOrPropertyWorker(symbol, checkMode);
        // For a contextually typed parameter it is possible that a type has already
        // been assigned (in assignTypeToParameterAndFixTypeParameters), and we want
        // to preserve this type.
        if (!links.type && !(checkMode && checkMode !== CheckMode.Normal)) {
            links.type = result;
        }
    }
    return result;
}

Further issues

Although this PR resolves common cases like the one above, but in cases like below false errors still occur. I didn't dig more to fix such issues because handling them would, in my opinion, clutter the type-checker without significant value in return due to the rarity of such usages. Please correct me if I'm wrong.

const [a, b = (() => 1 + a)()] = [0];

babakks avatar Sep 01 '22 12:09 babakks