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 declarations are allowed in generic constraints, but do not infer generic constraint types #41040

Open
lazytype opened this issue Oct 11, 2020 · 2 comments
Labels
Bug A bug in TypeScript
Milestone

Comments

@lazytype
Copy link

lazytype commented Oct 11, 2020

TypeScript Version: 4.0.2

Search Terms: generic constraint, extends infer

Code

type InferGenericConstraint<Fn> = 
    Fn extends <T extends infer Constraint>(arg: T) => any
        ? Constraint
        : never;

type GenericFunctionExample = <T extends number>(arg: T) => void;

type InferredConstraint = InferGenericConstraint<GenericFunctionExample>;

Expected behavior:

  • Preferred: InferredConstraint is number.
  • Alternative: infer declaration is disallowed within a generic constraint clause.

Actual behavior: InferredConstraint is never

Playground Link: https://tsplay.dev/gWoYlN

Related Issues: #1213

@krryan
Copy link

krryan commented Nov 26, 2020

In version 4.2.0-dev.20201115, InferredConstraint is unknown rather than never. I tried a large number of variations, but none of them can work around the fundamental fact that the type inferred for the constraint just isn’t right.

Things I tried:

type ConstraintOf<Fn extends <S>(arg: S) => any> = Fn extends <S extends infer Constraint>(arg: S) => any
  ? Constraint
  : never;
type ConstraintOf<Fn extends <S extends unknown>(arg: S) => any> = Fn extends <S extends infer Constraint>(arg: S) => any
  ? Constraint
  : never;
type ConstraintOf<Fn extends <S extends Constraint, Constraint>(arg: S) => any> = Fn extends <S extends infer Constraint>(arg: S) => any
  ? Constraint
  : never;

In every case, ConstraintOf<<S extends { foo: 'bar' }>(arg: S): void> evaluates to unknown.

@krryan
Copy link

krryan commented Nov 26, 2020

Well, I found a workaround.

type ConstraintOf<Fn extends <S extends any>(arg: S) => any> = Fn extends (arg: infer Arg) => any ? Arg : never;

Now ConstraintOf<<T extends number>(arg: T) => void> evaluates to number. So that solves the problem that @lazytype was working on.

The bug should stay open, though, because as far as I can tell, the other variations on this idea should have worked, too, and it’s kind of madness that this one worked and those didn’t. If anything, this version makes way less sense. What’s occurring here is that trying to test Fn against (arg: infer Arg) => any seems to “fix” S as the broadest possible value, here number, before moving on—and so the Arg has that value. This works, but is pretty weird and counter-intuitive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

No branches or pull requests

3 participants