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 can't share generic with base class #13979

Closed
maier49 opened this issue Feb 9, 2017 · 3 comments
Closed

Mixin can't share generic with base class #13979

maier49 opened this issue Feb 9, 2017 · 3 comments
Labels
Duplicate An existing issue was already created

Comments

@maier49
Copy link

maier49 commented Feb 9, 2017

TypeScript Version: 2.2.0-dev.20170209

Code

export class GenericClass<T> {
	value: T;
}
export interface GenericTrait<T> {
	newGenericValue: T;
}

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

export function SimpleMixin<C extends Constructable>(base: C): C & Constructor<GenericTrait<any>> {
	return class extends base {
		newGenericValue: any;
		constructor(...args: any[]) {
			super(...args);
		}
	};
}

class Child<T> extends GenericClass<T> {
	child: T;
	constructor(options: { childValue: string }) {
		super();
	}
}

const SimpleMixedClass = SimpleMixin(Child);

let simpleMixedInstance = new SimpleMixedClass<string>({ childValue: 'three' });
// Constructor is maintained
//new SimpleMixedClass(3); // Compilation error - good
// Generic is maintained
//simpleMixedInstance.child = 3; // Compilation error - good
// New generic is lost
simpleMixedInstance.newGenericValue = 3; // Should be a compilation error

My attempt at a workaround

export function MixinGeneric<C extends GenericClass<any>>(base: Constructor<C>): { new <T>(): (GenericClass<T> & GenericTrait<T> & C) } {
	return <any> class extends (base as Constructor<GenericClass<any>>) {
		newGenericValue: any;
		constructor(...args: any[]) {
			super(...args);
		}
	};
}
const MixedClass = MixinGeneric(Child);
// Child constructor is lost
// let mixedInstance = new MixedClass<string>({ childValue: 'value' }); // Compilation error - bad
let mixedInstance = new MixedClass<string>();
// Child generic type is lost
mixedInstance.child = { any: 'value' }; // Should be a compilation error
// New generic type is maintained
// mixedInstance.newGenericValue = { anything: 'value' }; // Compilation error - good

Expected behavior:
While I'm not sure if it's the expected behavior currently, the desired behavior is that the generic provided at instantiation time to the SimpleMixedClass will be used as the generic for the GenericTrait as well as the GenericClass.

Actual behavior:

The generic for the GenericTrait is set to any.

The second code example is my attempt at a workaround, but in that case the constructor/generic for any extensions to the targeted base class are lost.

@dylans
Copy link

dylans commented Feb 14, 2017

Any thoughts on this one for TS 2.2 or 2.3? We're in the process of seeing if there are any other issues in switching much of Dojo 2 from dojo/compose to using TS 2.2 classes now that it's easier to support mixins and compositional classes. Thanks!

@ahejlsberg
Copy link
Member

Similar to here, you need higher kinded types to represent that pattern since you're abstracting both over the constructor type and the type argument for the constructor type.

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label May 24, 2017
@zpdDG4gta8XKpMCd
Copy link

@ahejlsberg please consider higher kinded types as you next big feature

@RyanCavanaugh RyanCavanaugh added Duplicate An existing issue was already created and removed Needs Investigation This issue needs a team member to investigate its status. labels Sep 16, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants