Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #55632 issue (No type inferrence of callback arguments inside a tuple union type) #60434

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

fwolff
Copy link

@fwolff fwolff commented Nov 6, 2024

Passes all existing test cases and Airtable codebase ("Identicality" checks are probably quite rare so unsurprising). Creating this in the hopes that we can use the test infra on this repo to run this against the corpus of other open source libraries.

  • There is an associated issue in the Backlog milestone (required)
  • Code is up-to-date with the main branch
  • You've successfully run hereby runtests locally
  • There are new or updated unit tests validating the change

Fixes #55632.

In summary, the PR adds a new method:

function discriminateContextualTypeByArrayElements(node: ArrayLiteralExpression, contextualType: UnionType) {
    const key = `D${getNodeId(node)},${getTypeId(contextualType)}`;
    const cachedType = getCachedType(key);
    if (cachedType)
        return cachedType;

    const elementsLength = node.elements.length;
    const filteredType = filterType(contextualType, type => {
        if (!isTupleLikeType(type))
            return true;
        if (isTupleType(type))
            return elementsLength >= type.target.minLength && (!!(type.target.combinedFlags & ElementFlags.Variable) || elementsLength <= type.target.fixedLength);
        const properties = getPropertiesOfType(type);
        if (elementsLength > properties.length || elementsLength < properties.reduce((c, p) => p.flags & SymbolFlags.Optional ? c : ++c, 0))
            return false;
        for (let i = 0; i < elementsLength; i++) {
            if (!some(properties, p => p.escapedName === ("" + i) as __String))
                return false;
        }
        return true;
    });

    if (filteredType.flags & TypeFlags.Never)
        return setCachedType(key, contextualType);
    if (!(filteredType.flags & TypeFlags.Union))
        return setCachedType(key, isTupleLikeType(filteredType) ? filteredType : contextualType);

    return setCachedType(key, discriminateTypeByDiscriminableItems(
        filteredType as UnionType,
        node.elements.map((element, index) => {
            const name = ("" + index) as __String
            return isPossiblyDiscriminantValue(element) && isDiscriminantProperty(filteredType, name) ?
                [() => getContextFreeTypeOfExpression(element), name] as const :
                undefined
        }).filter(discriminator => !!discriminator),
        isTypeAssignableTo,
    ));
}

...and calls it in the existing getApparentTypeOfContextualType method:

if (apparentType.flags & TypeFlags.Union) {
    if (isObjectLiteralExpression(node))
        return discriminateContextualTypeByObjectMembers(node, apparentType as UnionType);
    if (isJsxAttributes(node))
        return discriminateContextualTypeByJSXAttributes(node, apparentType as UnionType);
// -------
    if (isArrayLiteralExpression(node))
        return discriminateContextualTypeByArrayElements(node, apparentType as UnionType);
// -------
}
return apparentType;

It also adds a new unit tests file tests/cases/compiler/tupleTypeInference3.ts with the code failing in #55632 and other related tests.

The PR doesn't provide anything for code completion, which could be handled by #58571.

Question: I use the isTupleLikeType method to match actual tuple types and tuple-like types like type T = { 0: 1, 1: (a: boolean) => void } (see the new unit tests file). The isTupleLikeType checks also for array-like type, but I was unable to create any such type. Can anybody tell me how to create such types and what I should do with them?

@typescript-bot typescript-bot added the For Backlog Bug PRs that fix a backlog bug label Nov 6, 2024
@fwolff
Copy link
Author

fwolff commented Nov 6, 2024

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Status: Not started
Development

Successfully merging this pull request may close these issues.

No type inferrence of callback arguments inside a tuple union type
3 participants