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

...infer X extends TypeParameter[] in conditional type inappropriate binding #54197

Closed
webstrand opened this issue May 9, 2023 · 1 comment Β· Fixed by #59760
Closed

...infer X extends TypeParameter[] in conditional type inappropriate binding #54197

webstrand opened this issue May 9, 2023 · 1 comment Β· Fixed by #59760
Assignees
Labels
Fix Available A PR has been opened for this issue
Milestone

Comments

@webstrand
Copy link
Contributor

webstrand commented May 9, 2023

Bug Report

πŸ”Ž Search Terms

conditional type, extends, infer, spread, tuple

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about extends

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type Foo<K, T extends readonly unknown[]> = T extends readonly [any, ...infer X extends readonly unknown[]] ? X : never;
type Bar<K, T extends readonly unknown[]> = T extends readonly [any, ...infer X extends readonly K[]] ? X : never;
type Baz<K, T extends readonly unknown[]> = T extends readonly [any, ...infer X extends readonly (K | "a" | "b")[]] ? X : never;

type x = Foo<"a" | "b", ["a", "b", "b"]>
//   ^? - type x = ["b", "b"]
type y = Bar<"a" | "b", ["a", "b", "b"]> 
//   ^? - type y = readonly ("a" | "b")[]
type z = Baz<"a" | "b", ["a", "b", "b"]>
//   ^? - type z = ["b", "b"]

πŸ™ Actual behavior

The conditional types do not produce the same output:

type x = Foo<"a" | "b", ["a", "b", "b"]> // ["b", "b"]
type y = Bar<"a" | "b", ["a", "b", "b"]> // readonly ("a" | "b")[]
type z = Baz<"a" | "b", ["a", "b", "b"]> // ["b", "b"]

πŸ™‚ Expected behavior

The conditional types should all produce the same output. The fact that K is a type parameter should not affect the output.

type x = Foo<"a" | "b", ["a", "b", "b"]> // ["b", "b"]
type y = Bar<"a" | "b", ["a", "b", "b"]> // ["b", "b"]
type z = Baz<"a" | "b", ["a", "b", "b"]> // ["b", "b"]

Alternatively if that is infeasible for technical reasons, the conditional type should fail. Inferring the constraint makes traversing the tuple impossible.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label May 10, 2023
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone May 10, 2023
@typescript-bot typescript-bot added the Fix Available A PR has been opened for this issue label May 10, 2023
@warriordog
Copy link

warriordog commented Jun 2, 2023

Here's another reproduction, showing how it works if the tuple is reversed.
I've tested in 5.0.4 and 5.1.3.

type Heads<T extends any[]> = T extends [... infer Rest, any] ? Rest : never;
type Tails<T extends any[]> = T extends [any, ... infer Rest] ? Rest : never;

// Expected: [1, 2]
// Actual:   never
type heads = Heads<[1, 2, 3]>;

// Expected: [2, 3]
// Actual:   [2, 3]
type tails = Tails<[1, 2, 3]>;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment