Description
I see a challenge currently in TypeScript in supporting alternative methods of OO programming. The topic has come up in several forms before, and there isn't a clear solution. Here is a summary of related tickets all in a similar problem space:
- Mixin language support (with toy implementation) #2919 - Mixin language support (with toy implementation)
- Feature suggestion: treat prototype assignments like merging type declarations #4038 - Treat prototype assignments like merging type declarations
- Feature Request / Proposal: Traits #311 - Feature Request / Proposal: Traits
- Partial classes #563 - Partial Classes
- Proposal: structural overloading for interfaces #4302 - Proposal: structural overloading for interfaces
Currently, the only ways of "defining" types at design time:
- Interfaces - they support extension and are open ended
- Classes - supports traditional OO inheritance
- Abstract Classes - like Interfaces, but called Abstract Classes 😉
- Generics - Allows parameterisation of types
- Unions - Allow concatenation of types
- Intersections - More like a merge type actually 😉
In JavaScript, I can support other non-Inheritance and non-OO programming paradigms, but if I decide to extend those in TypeScript, I almost certainly will lose the static typing
For example, I can create a "composition/factory" in JavaScript, that makes it easy for me to "compose" functionality:
var compose = require('compose');
var factory = compose(function () { /* init */ }, {
foo: 'bar'
}, {
bar: 1
});
var a = factory.create();
But if I wanted all sorts of TypeScript goodness, it essentially starts to get really complicated. I could of sort of used Generics with Intersections, but the actual definition of the type and the implementation are decoupled and users of the compose library would have to learn some "arbitrary" syntax.
Now if there was a way, behind the scenes, to programatically merge/mixin types and modify them, I could abstract the user from the implementation and it would just work... I would love to be able to write something like this in TypeScript:
import compose from 'compose';
class Foo {
foo: string = 'bar';
}
interface Bar {
bar: number;
}
let factory = compose(function () { /* init */ },
Foo,
Bar
);
let a = factory.create();
Another example would be Aspect Oriented Programming. It is easy to support in JavaScript and actually the Decorators help a lot in TypeScript, but the challenge is that Decorators don't modify the type definition, and with after and around advice the return type can be modified. There is currently no way of expressing this in TypeScript.
There are probably loads of other patterns that are implemented in JavaScript which we cannot easily use in TypeScript and currently, it means us in the community are like a load of needy children, saying "I want, I want, I want, I need, I need, I need". Obviously a lot of this boils down to pseudo-religious debates, but without design time programmatic access to accessing and manipulating the types, we are going to constantly be running into these conflicts.
I am not sure of what the most logical and clean way the TypeScript team could implement something like this, but hopefully the team sees the need...