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

Carry over source constraints to the inferred type parameter #51108

Open
5 tasks done
Andarist opened this issue Oct 8, 2022 · 2 comments
Open
5 tasks done

Carry over source constraints to the inferred type parameter #51108

Andarist opened this issue Oct 8, 2022 · 2 comments
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript
Milestone

Comments

@Andarist
Copy link
Contributor

Andarist commented Oct 8, 2022

Suggestion

πŸ” Search Terms

infer, constraints, generic, extends

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

It would be nice if the infer T wouldn't lose the source constraint. I've always wondered why this is lost and couldn't find any explanation behind this in the issues etc. @DanielRosenwasser has suggested here that it might be worth opening an issue about this.

Note that since 4.7 it is possible to add extends Constraints on infer Type Variables - the feature request here is different because the constraint is known upfront. Such extends would still be useful with the proposed feature because it can be used to limit the number of conditional types both when the source constraint is completely unbound/unknown or when you simply want to match a subtype of the source constraint.

πŸ“ƒ Motivating Example

I've bumped into this on several occasions, even such a simple doesn't compile right now:

type Prefix<Prefix extends string, Input extends string> = `${Prefix}${Input}`;

type Test<T extends string[]> = T extends [infer Head, ...any[]]
  ? Prefix<"foo", Head> // Type 'Head' does not satisfy the constraint 'string'.(2344) This type parameter might need an `extends string` constraint.
  : never;

πŸ’» Use Cases

It would allow us to skip a lot of error-prone repetition when working with the infer keyword.

@RyanCavanaugh RyanCavanaugh added Suggestion An idea for TypeScript Experimentation Needed Someone needs to try this out to see what happens labels Oct 10, 2022
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Oct 10, 2022
@Enva2712
Copy link

I've run into this as well, most recently with this type:

type DeepKeyedBy<
  T extends Record<Ks[number], string | number | symbol>,
  Ks extends [] | [keyof T, ...(keyof T)[]]
> = Ks extends [infer Head, ...infer Tail]
  ? { [V in T as V[Head]]: DeepKeyedBy<V, Tail> }
  : T[];

Using a ts-ignore in the type makes it work externally, and the constraints can always be repeated with conditional types, but it would be nice if this just workedtm

@Andarist
Copy link
Contributor Author

Andarist commented Feb 22, 2023

Today getInferredTypeParameterConstraint is based on syntactic matching. Therefore it might be quite hard to fix this holistically without rethinking the approach that is being used there.

In #43649 @weswigham mentions this:

More generally, if we wanted to move from syntactic matching for this case (and broaden how applicable this fix is), we could do inference between the source and target sides of the containing uninstantiated conditional, and rely on inference to match the infer X location up to an appropriate constraint location instead; but doing so in general could be breaky in the community, since using infer constraints to break constraint relationships in our calculations is relatively common.

The "using infer constraints to break constraint relationships in our calculations is relatively common" bit is especially interesting here. What are the use cases for this? Is it only about avoiding recursion limits? Or is there more to it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experimentation Needed Someone needs to try this out to see what happens Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants