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

Mixin expected argument type resolves to never when constrained to constructor of type whose property is typed via a type parameter #34979

Open
dsherret opened this issue Nov 7, 2019 · 0 comments
Labels
Needs Investigation This issue needs a team member to investigate its status.

Comments

@dsherret
Copy link
Contributor

dsherret commented Nov 7, 2019

TypeScript Version: 3.8.0-dev.20191105

Search Terms: mixin 3.7 type

Code

import * as ts from "typescript";

type Constructor<T> = new (...args: any[]) => T;

export class Node<NodeType extends ts.Node = ts.Node> {
    compilerNode!: NodeType;
}

// BindingNamedNode
export interface BindingNamedNode {
    getName(): string;
}

export function BindingNamedNode<
    TCompilerNode extends ts.Node & { name: ts.BindingName; },
    TBase extends Constructor<Node<TCompilerNode>>
>(
    Base: TBase
): Constructor<BindingNamedNode> & TBase {
    return {} as any;
}

// InitializerableNode
export interface InitializerableNode {
    removeInitializer(): this;
}

export function InitializerableNode<
    TCompilerNode extends ts.Node & { initializer?: ts.Expression; },
    TBase extends Constructor<Node<TCompilerNode>>
>(
    Base: TBase
): Constructor<InitializerableNode> & TBase {
    return {} as any;
}

// BindingElement
export class BindingElement extends InitializerableNode(BindingNamedNode(Node))<ts.BindingElement> {
}

Other Code

Or my original code... I think it's more correct to do the above, but should either of these error?

import * as ts from "typescript";

type Constructor<T> = new (...args: any[]) => T;

export class Node<NodeType extends ts.Node = ts.Node> {
    compilerNode!: NodeType;
}

// BindingNamedNode
export type BindingNamedNodeExtensionType = Node<ts.Node & { name: ts.BindingName; }>;

export interface BindingNamedNode {
    getName(): string;
}

export function BindingNamedNode<T extends Constructor<BindingNamedNodeExtensionType>>(
    Base: T
): Constructor<BindingNamedNode> & T {
    return {} as any;
}

// InitializerableNode
export type InitializerableNodeExtensionType = Node<ts.Node & { initializer?: ts.Expression; }>;

export interface InitializerableNode {
    removeInitializer(): this;
}

export function InitializerableNode<T extends Constructor<InitializerableNodeExtensionType>>(
    Base: T
): Constructor<InitializerableNode> & T {
    return {} as any;
}

// BindingElement
export class BindingElement extends InitializerableNode(BindingNamedNode(Node))<ts.BindingElement> {
}

Expected behavior: No errors, as in TS < 3.7

TS 3.6.3 Playground

Actual behavior:

TS2345: Argument of type 'typeof Node' is not assignable to parameter of type 'never'.

export class BindingElement extends InitializerableNode(BindingNamedNode(Node))<ts.BindingElement> {
                                                                         ~~~~
}

Playground Link: TS 3.8.0-dev.20191105 Playground

Other Comments

The issue does not occur when the type parameter is inlined (Playground).

Also, I wouldn't be surprised if I was doing something wrong here, but this has worked in the past.

Workaround

Pass the class constructor into a function typed like so and the compile error goes away (Playground):

const createBase = <T extends typeof Node>(ctor: T) => InitializerableNode(BindingNamedNode(ctor));
export class BindingElement extends createBase(Node)<ts.BindingElement> {
}
@andrewbranch andrewbranch added the Needs Investigation This issue needs a team member to investigate its status. label Dec 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Investigation This issue needs a team member to investigate its status.
Projects
None yet
Development

No branches or pull requests

2 participants