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

Conditional types infer the wrong type for generic constraints #41677

Closed
krryan opened this issue Nov 24, 2020 · 3 comments
Closed

Conditional types infer the wrong type for generic constraints #41677

krryan opened this issue Nov 24, 2020 · 3 comments

Comments

@krryan
Copy link

krryan commented Nov 24, 2020

TypeScript Version: 4.2.0-dev.20201115

Search Terms: conditional type generic constraint

Code

type ConstraintOf<Fn extends <S>(arg: S) => any> = Fn extends <S extends infer Constraint>(arg: S) => any ? Constraint : never;
type Test = ConstraintOf<<S extends { foo: 'bar' }>(arg: S) => 'baz'>;

As a variant, also tried

type ConstraintOf<Fn extends <S extends unknown>(arg: S) => any> = Fn extends <S extends infer Constraint>(arg: S) => any ? Constraint : never;
type Test = ConstraintOf<<S extends { foo: 'bar' }>(arg: S) => 'baz'>;

and

type ConstraintOf<Fn extends <S extends Constraint, Constraint>(arg: S) => any> = Fn extends <S extends infer Constraint>(arg: S) => any ? Constraint : never;
type Test = ConstraintOf<<S extends { foo: 'bar' }>(arg: S) => 'baz'>;

and

type ConstraintOf<Fn extends <S extends Constraint, Constraint>(arg: S) => any> = Constraint;
type Test = ConstraintOf<<S extends { foo: 'bar' }>(arg: S) => 'baz'>;

None of these variants changed the observed behavior.

Expected behavior:
The type of Test is { foo: 'bar' }.

Actual behavior:
The type of Test is unknown. This is particularly problematic because the constraint on the function implies a minimum requirement for safely calling it, which is lost when the type becomes unknown and thus it would compile without error for any value passed in.

Playground Link:
Unavailable: in the playground, <S extends { foo: 'bar' }>(arg: S) => 'baz' cannot be passed to ConstraintOf as it is not considered to extend <S>(arg: S) => any in the first place. Removing the constraint on ConstraintOf itself yields never as it just fails the extends check in the conditional type.

Related Issues: None I’m aware of.

Purpose:
My goal here is to be able to take a generic function (known to be of the form <S extends Foo>(arg: S) => Bar, where Foo and Bar can vary, and be able construct a new function that takes the same argument, with the same constraint, but returns something else.

Specifically, I am working on a compose function that can handle (this one specific case of) generic functions, i.e.

export function compose<Constraint, A, B>(a: <S extends Constraint>(arg: S) => A, b: (a: A) => B): <S extends Constraint>(arg: S) => B;

Generalizing this requires higher-order kinds, but it seems to me that this specific use-case should not. I just want to extract the constraint (known to be that one single value), and use it in another type.

This almost works:

declare function first<S extends { foo: 42; }>(arg: S): S & { bar: 3; };
declare function second<S>(arg: S): S & { baz: 'test' };
const test = compose(first, second);

Then test has the type <S extends unknown>(arg: S) => S & { bar: 3; } & { baz: 'test' }.

@MartinJohns
Copy link
Contributor

This looks like a duplicate of #39736.

@krryan
Copy link
Author

krryan commented Nov 24, 2020

I disagree—that issue is described as an abbreviation syntax, which this is not. Furthermore, it’s not at all clear that

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

would work any better in the world where #39736 has been implemented than my own variants above do here.

@krryan krryan changed the title Conditional types cannot extract constraints on generics Conditional types infer the wrong type for generic constraints Nov 25, 2020
@krryan
Copy link
Author

krryan commented Nov 26, 2020

On the other hand, it is a duplicate of #41040.

@krryan krryan closed this as completed Nov 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants