fasttime / polytype Goto Github PK
View Code? Open in Web Editor NEWDynamic multiple inheritance for JavaScript and TypeScript. Without mixins.
License: ISC License
Dynamic multiple inheritance for JavaScript and TypeScript. Without mixins.
License: ISC License
I was using super.class(BaseClass)
in may cases and it handles typing correctly.
I see: protected class<U extends T>(type: U): U;
in the .d.ts
file
I was trying out getPrototypeListOf
and realized that I was getting all the baseClass as any
And I saw: export function getPrototypeListOf(o: any): any[];
in the .d.ts
file
So, creating this issue to potentially improve the typing here to get more accurate types
PS: I have no idea if it is possible at all :)
I did try this:
export class ChildClass extends classes(BaseClass1, BaseClass2) {
myFunc() {
(getPrototypeListOf(ChildClass) as (BaseClass1 | BaseClass2)[]).forEach(baseClass => {
baseClass.myFunc()
})
}
}
NOTE: This will assume baseClass
has the type (typeof BaseClass1 | typeof BaseClass2)
So, if all my base classes implement a particular function - then this work out quite well
Doing: getPrototypeListOf(ChildClass) as [BaseClass1, BaseClass2]
would also work and be more accurate
When we launch the following command:
ng serve --prod --source-map
We get the following error:
ERROR in main.d558a3403cc855f52798.js from Terser
Unexpected token: punc ()) [./node_modules/polytype/lib/polytype.mjs:117,0][main.d558a3403cc855f52798.js:52044,4]
Hi, I am working on an angular project which uses typescript and was trying to use polytype.
I have a case where I am trying to use polytype in something like:
class WriteService<T> {
create(t: T): T;
update(t: T): T;
}
export class UserService extends WriteService<UserModel> {
...
}
i.e. my BaseService is defining a bunch of functions for my Type - and then I inherit this into a UserService with my UserModel.
When I try to use polytype:
export class UserService extends classes(WriteService<UserModel>) {
...
}
it gives me an error - so, I tried a few variations of this (without much understanding of the magic polytype does), but was not able to figure out how to handle this case with polytype.
Some variations I tried:
export class UserService<T> extends classes(WriteService<T>)
classes
an explicit type: export class UserService extends classes<[WriteService<UserModel>]>(WriteService)
classes
an explicit type: export class UserService extends classes<[typeof WriteService<UserModel>]>(WriteService)
I guess the argument to classes
is a class. So, I can't pass the <>
there... ?
I've been trying to figure out inheritance / mixin approach for the past few days.
And I've seen a few methods around
polytype seems to be the most robust approach I have come acorss based on the documentation so far.
I was wondering if there was some nice comparison of some of the common approaches and pitfalls or other approaches that could exist ?
For example -
Object.assign(MyClass.prototype, MyMixin);
(which does not allow me to use super(), instanceof, doesnt handle typing, etc.)And so on.
Hi
In general manipulating global isn't a good idea (in some cases it does have value, so won't argue that) and it would be safer if we can just
// explicit usage
import { classes } from 'polytype';
// global usage
import defineGlobally from 'polytype';
defineGlobally();
// or
import 'polytype/global';
I have a component that navigate to other page when finish the method ngOnInit:
import { Component, OnInit } from '@angular/core';
import { ClassA } from './classA';
import { ClassB } from './classB';
import { classes } from 'polytype';
import { ClassAService} from './classA.service';
import { ClassBService} from './classB.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.sass']
})
export class AppComponent extends classes(ClassA, ClassB) {
constructor(
classAService: ClassAService,
classBService: ClassBService
) {
super(['classAService'], ['classBService']);
}
ngOnInit(): void {
// Do something and navigate to other page
}
}
The issue come when both extended classes have ngOnDestroy method, only the first class execute ngOnDestroy and should both classes execute It. I need to do the following to make it works correctly but I think It is not the best option:
ngOnInit(): void {
// Navigate to other page
super.class(ClassB).ngOnDestroy();
}
Thank you for your great work I look forward to your answer.
Hey
I was trying to use this library to do something a tad bit weird and ran into an error.
Cannot assign an abstract constructor type to a non-abstract constructor type
To recreate the bug
abstract class AbstractClass {}
class Test extends classes(AbstractClass) {}
// Argument of type 'typeof AbstractClass' is not assignable to parameter of type 'SuperConstructor'.
// Cannot assign an abstract constructor type to a non-abstract constructor type.ts(2345)
Not sure if this is just a typing bug, ie the package supports abstract classes but the types have to be updated or if they package itself doesn't have abstract class support
When i use Polytype with Angular 8 i get this error:
Unexpected value 'AppComponent' declared by the module 'AppModule'
AppComponent:
import { Component, OnInit } from '@angular/core';
import { ClassA } from './classA';
import { ClassB } from './classB';
import { classes } from 'polytype';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.sass']
})
export class AppComponent extends classes(ClassA, ClassB) implements OnInit {
constructor() {
super(['hola'], ['adios']);
}
ngOnInit(): void {
this.printA();
this.printB();
}
}
AppModule
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
If I delete extends classes(ClassA, ClassB) everything works correctly
Hi,
I have created a simple angular-9 component and attempt to use polytype to extend a typescript Utils class.
I am using the following packages:
import { Component, OnInit,} from '@angular/core'
import { NgControl } from '@angular/forms'
import { classes } from 'polytype'
export class Utils {
// constructor() {} - does not work either if uncommented
onFocusInShowPendingValidationStatus( validationStatus: string, evernt?: Event ): string {
return validationStatus = 'pending'
}
onFocusOutValidationStatus( validationStatus: string, control: NgControl, event?: Event ): string {
return validationStatus = control.valid ? 'valid' : 'invalid'
}
onValueChangedValidationStatus( validationStatus: string, control: NgControl, event? ): string {
return validationStatus = control.valid ? 'valid' : 'invalid'
}
}
@Component(
{
selector: 'pim-poly-types',
template: `
<p>
poly-types works!
</p>
`,
styles: [],
} )
export class PolyTypesComponent extends classes( Utils ) implements OnInit {
constructor() {super() }
ngOnInit(): void {
}
}
However, I am consistently getting the following error that prevents the app from running. The app does compile though.
core.js:4117 ERROR TypeError: Constructor cannot be invoked without 'new' at Object.apply (polytype.mjs:43) at new PolyTypesComponent (poly-types.component.ts:36) at NodeInjectorFactory.PolyTypesComponent_Factory [as factory] (poly-types.component.ts:39) at getNodeInjectable (core.js:3956) at instantiateAllDirectives (core.js:8407) at createDirectivesInstances (core.js:7774) at ɵɵelementStart (core.js:14518) at Module.ɵɵelement (core.js:14569) at LoginFormComponent_Template (login-form.component.html:85) at executeTemplate (core.js:7747) defaultErrorLogger @ core.js:4117 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.ErrorHandler.handleError @ core.js:4165 (anonymous) @ core.js:29098 push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:386 push.../../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:143 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.NgZone.runOutsideAngular @ core.js:28074 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.ApplicationRef.tick @ core.js:29098 (anonymous) @ core.js:28954 push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:386 onInvoke @ core.js:28134 push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:385 push.../../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:143 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.NgZone.run @ core.js:28029 next @ core.js:28953 schedulerFn @ core.js:25506 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:192 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next @ Subscriber.js:130 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next @ Subscriber.js:76 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:53 push.../../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @ Subject.js:47 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.EventEmitter.emit @ core.js:25488 checkStable @ core.js:28084 onHasTask @ core.js:28148 push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.hasTask @ zone.js:441 push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate._updateTaskCount @ zone.js:462 push.../../node_modules/zone.js/dist/zone.js.Zone._updateTaskCount @ zone.js:284 push.../../node_modules/zone.js/dist/zone.js.Zone.runTask @ zone.js:205 drainMicroTaskQueue @ zone.js:601 push.../../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:507 invokeTask @ zone.js:1671 globalZoneAwareCallback @ zone.js:1697 core.js:4117 ERROR Error: Uncaught (in promise): TypeError: Constructor cannot be invoked without 'new' TypeError: Constructor cannot be invoked without 'new' at Object.apply (polytype.mjs:43) at new PolyTypesComponent (poly-types.component.ts:36) at NodeInjectorFactory.PolyTypesComponent_Factory [as factory] (poly-types.component.ts:39) at getNodeInjectable (core.js:3956) at instantiateAllDirectives (core.js:8407) at createDirectivesInstances (core.js:7774) at ɵɵelementStart (core.js:14518) at Module.ɵɵelement (core.js:14569) at LoginFormComponent_Template (login-form.component.html:85) at executeTemplate (core.js:7747) at resolvePromise (zone.js:832) at resolvePromise (zone.js:784) at zone.js:894 at ZoneDelegate.push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421) at Object.onInvokeTask (core.js:28122) at ZoneDelegate.push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420) at Zone.push.../../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188) at drainMicroTaskQueue (zone.js:601) at ZoneTask.push.../../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:507) at invokeTask (zone.js:1671) defaultErrorLogger @ core.js:4117 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.ErrorHandler.handleError @ core.js:4165 next @ core.js:28692 schedulerFn @ core.js:25506 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:192 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next @ Subscriber.js:130 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next @ Subscriber.js:76 push.../../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next @ Subscriber.js:53 push.../../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @ Subject.js:47 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.EventEmitter.emit @ core.js:25488 (anonymous) @ core.js:28157 push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:386 push.../../node_modules/zone.js/dist/zone.js.Zone.run @ zone.js:143 push.../../node_modules/@angular/core/__ivy_ngcc__/fesm5/core.js.NgZone.runOutsideAngular @ core.js:28074 onHandleError @ core.js:28157 push.../../node_modules/zone.js/dist/zone.js.ZoneDelegate.handleError @ zone.js:390 push.../../node_modules/zone.js/dist/zone.js.Zone.runGuarded @ zone.js:157 _loop_1 @ zone.js:701 api.microtaskDrainDone @ zone.js:708 drainMicroTaskQueue @ zone.js:608 push.../../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask @ zone.js:507 invokeTask @ zone.js:1671 globalZoneAwareCallback @ zone.js:1697
theres an empty catch block in polytype.cjs file at line 526, it works fine without issues but some linters are now allowing it to be uploaded to proxy repos. can we add a simple command to handle the exception?
Hi,
I am trying to use polytype in my angular9/typescript project
Consider the following code for single class inheritance in typescript:
export class AbstractBaseComponent{
form: FormGroup
}
@Component ({
selector: 'pim'
template: `
<form [formGroup] = 'form'>
</form>
`
})
export class PimComponent extends AbstractBaseComponent {
// the form of the template is referenced by the form of the Abstract
BaseComponent as expected
}
For polytype multi-inheritance
@Component ({
selector: 'pim'
template: `
<form [formGroup] = 'form'>
</form>
`
})
export class PimComponent extends classes(AbstractBaseComponent) {
// the form of the template is NOT referenced by the form of the AbstractBaseComponent as expected
}
What am I doing incorrectly. My Webstorm IDE flag the template form as error (Is this IDE failure or polytype failure?)
Thanks for your help
Hi Francesco!
Thank you for Polytype, it's very well done and carefully explained. 😃
I'm experiencing the following issue, when dealing with binds in base classes.
If I use only extends in this scenario it works as expected.
import { classes } from 'js/polytype'
class TestDefault {
constructor() {
this.print = this.print.bind(this)
console.log('TestDefault constructor')
}
print() {
console.log('TestDefault Print')
}
}
class Test extends classes(TestDefault) {
constructor() {
super()
this.someVar = 6
console.log('Test constructor')
}
print() {
console.log('Test Print', this.someVar)
super.print()
}
}
const test = new Test()
test.print()
This will print:
TestDefault constructor
Test constructor
Test Print undefined
TestDefault Print
Instead of Test Print undefined, it should be be Test Print 6.
I'm guessing the binding only binds the instance of TestDefault.
I've tried to bind again print in Test, but nothing changed.
Do you know what can be done to solve this?
Thank you!
Please add in the documentation that Typescript >=4 is required :)
Steps to reproduce:
const Arrow = require("crocks/Arrow");
class K extends classes(Arrow, Object) {
compose(...args) {
console.log("THIS WILL NOT RUN");
return super.compose(...args);
}
}
const k = new K([x => x]);
const l = new K([x => x]);
k.compose(l); // returns an instance of Arrow but no console.log
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.