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

Support higher order inferences for constructor functions #31116

Merged
merged 8 commits into from Apr 30, 2019

Conversation

ahejlsberg
Copy link
Member

@ahejlsberg ahejlsberg commented Apr 25, 2019

This PR expands on #30215 to support higher order inferences for constructor functions and to permit function type arguments to higher order composition functions to have other members in addition to their single call signature.

Some examples:

declare class Point {
    constructor(x: number, y: number);
    readonly x: number;
    readonly y: number;
}

declare class Bag<T> {
    constructor(...args: T[]);
    contains(value: T): boolean;
    static foo: string;
}

function asFunction<A extends any[], B>(cf: new (...args: A) => B) {
    return (...args: A) => new cf(...args);
}

const newPoint = asFunction(Point);  // (x: number, y: number) => Point
const newBag = asFunction(Bag);      // <T>(...args: T[]) => Bag<T>
const p1 = new Point(10, 20);        // Point
const p2 = newPoint(10, 20);         // Point
const bag1 = new Bag(1, 2, 3);       // Bag<number>
const bag2 = newBag('a', 'b', 'c');  // Bag<string>

declare class Component<P> {
    props: P;
    constructor(props: P);
}

type ComponentClass<P> = new (props: P) => Component<P>;

declare function myHoc<P>(C: ComponentClass<P>): ComponentClass<P>;

type GenericProps<T> = { foo: number, stuff: T };

declare class GenericComponent<T> extends Component<GenericProps<T>> {}

// const GenericComponent2: new <T>(props: GenericProps<T>) => Component<GenericProps<T>>
const GenericComponent2 = myHoc(GenericComponent);

The rules for determining when higher order inferences occur are revised as follows. Given a generic function f of type <…>(…, x: P, …) => R, and an argument expression a of a generic function type A, in a call expression f(…, a, …) the type parameters of A are propagated onto the inferred result type of the function call if:

  • P is a function type with no type arguments, a single call or construct signature, and no other members, and
  • R is a function type with no type arguments, a single call or construct signature, and no other members, and
  • A is function type with type arguments and a single call or construct signature that matches P (note that A is permitted to have other members), and
  • in the left-to-right processing of the function call arguments, no inferences have been made for any of the type parameters referenced in P.

Fixes #30650.

@ahejlsberg
Copy link
Member Author

@typescript-bot test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 25, 2019

Heya @ahejlsberg, I've started to run the extended test suite on this PR at fcd6f52. You can monitor the build here. It should now contribute to this PR's status checks.

@ahejlsberg
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 25, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at fcd6f52. You can monitor the build here. It should now contribute to this PR's status checks.

@ahejlsberg
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 25, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 4fe59dc. You can monitor the build here. It should now contribute to this PR's status checks.

@weswigham
Copy link
Member

The react-test-renderer failure is in master, so I think DT is clean.

@ahejlsberg
Copy link
Member Author

@typescript-bot run dt

@typescript-bot
Copy link
Collaborator

typescript-bot commented Apr 26, 2019

Heya @ahejlsberg, I've started to run the parallelized Definitely Typed test suite on this PR at 3e79e8d. You can monitor the build here. It should now contribute to this PR's status checks.

@guykr
Copy link

guykr commented Jun 18, 2019

Hi @RyanCavanaugh @ahejlsberg,
when trying to use this new mechanism with React's ComponentClass I noticed this does not actually work, the inferred type is actually: const GenericComponent2: ComponentClass<GenericProps<unknown>> not const GenericComponent2: new <T>(props: GenericProps<T>) => Component<GenericProps<T>>

Please find below an adapted example from the one in this PR:

declare class Point {
  constructor(x: number, y: number)
  readonly x: number
  readonly y: number
}

declare class Bag<T> {
  constructor(...args: T[])
  contains(value: T): boolean
  static foo: string
}

function asFunction<A extends any[], B>(cf: new (...args: A) => B) {
  return (...args: A) => new cf(...args)
}

const newPoint = asFunction(Point) // (x: number, y: number) => Point
const newBag = asFunction(Bag) // <T>(...args: T[]) => Bag<T>
const p1 = new Point(10, 20) // Point
const p2 = newPoint(10, 20) // Point
const bag1 = new Bag(1, 2, 3) // Bag<number>
const bag2 = newBag('a', 'b', 'c') // Bag<string>

declare class Component<P> {
  props: P
  constructor(props: P)
}

interface ComponentClass<P> {
  new (props: P): Component<P>
  thisWillBreakGenericInference?: boolean // <--- this is breaking the type inference
}

declare function myHoc<P>(C: ComponentClass<P>): ComponentClass<P>

type GenericProps<T> = { foo: number; stuff: T }

declare class GenericComponent<T> extends Component<GenericProps<T>> {}

// Should be:
// const GenericComponent2: new <T>(props: GenericProps<T>) => Component<GenericProps<T>>
// Actually: 
// const GenericComponent2: ComponentClass<GenericProps<unknown>>

const GenericComponent2 = myHoc(GenericComponent)

Link to playground:
The change I made is in line 31.

The issue here is that React's ComponentClass interface has a few optional members defined.

@ahejlsberg
Copy link
Member Author

@guykr-stratoscale That's a known limitation. See discussion in #30650 (comment).

jablko added a commit to jablko/TypeScript that referenced this pull request Oct 16, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Oct 19, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Oct 27, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 4, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 13, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 16, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 22, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 25, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 26, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 27, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 28, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Nov 29, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Dec 28, 2019
jablko added a commit to jablko/TypeScript that referenced this pull request Jan 21, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Jan 25, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Jan 25, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Jan 29, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 3, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 3, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 4, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 6, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 9, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 10, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 11, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 12, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 12, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 13, 2020
@2A5F 2A5F mentioned this pull request Feb 17, 2020
5 tasks
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 21, 2020
jablko added a commit to jablko/TypeScript that referenced this pull request Feb 22, 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

Successfully merging this pull request may close these issues.

Higher order type inference from generic React component
7 participants