Skip to content

Normalize variadic tuples with reduced never element type to never #59866

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Andarist
Copy link
Contributor

@Andarist Andarist commented Sep 5, 2024

an issue observed while investigating another one, see here

This solves an inconsistency problem that can be seen here (TS playground):

type Baseline = [...never];
//   ^? type Baseline = never

type Test<T extends unknown[]> = [...T];
type Input = [] & [string];
//   ^? type Input = never
type Result = Test<Input>;
//   ^? type Result = any[]

Baseline and Result should both be never.

@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Sep 5, 2024
@@ -17455,6 +17455,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// Spread variadic elements with tuple types into the resulting tuple.
forEach(elements, (t, n) => addElement(t, type.target.elementFlags[n], type.target.labeledElementDeclarations?.[n]));
}
else if (getReducedApparentType(type).flags & TypeFlags.Never) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this the code hits the last branch:

                else {
                    // Treat everything else as an array type and create a rest element.
                    addElement(isArrayLikeType(type) && getIndexTypeOfType(type, numberType) || errorType, ElementFlags.Rest, target.labeledElementDeclarations?.[i]);
                }

But a never type (and a reduced never type) don't have index types. So that getIndexTypeOfType returns undefined and the compiler ends up normalizing this to an anyType.

Note that getIndexTypeOfType leads to calling getReducedApparentType so this effectively just calls it a little bit more eagerly.

This also matches how getIndexedAccessTypeOrUndefined + getPropertyTypeForIndexType handle case like this:

type Test = ([] & [string])[number];
//   ^? type Test = never

Those functions also call getReducedApparentType and when the object type has TypeFlags.Never they return the object type itself. The small difference here is that I decided to return neverType. This seems like a better product of this normalization... but perhaps this should also return the type? The tests wouldn't mind this change (I checked).

An extra note: this could also be checked closer to the top of createNormalizedTupleType (where checkCrossProductUnion gets called) but it seemed me this extra branch here is easier to follow~.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Uncommitted Bug PR for untriaged, rejected, closed or missing bug
Projects
Status: Not started
Development

Successfully merging this pull request may close these issues.

2 participants