This project is read-only.

Modelling non-TypeScript inheritance

Topics: Language Specification
Oct 31, 2013 at 8:08 PM
Edited Oct 31, 2013 at 8:09 PM

I have been working with TypeScript for a few weeks now and one of the only real issues that I have faced has been figuring out how to properly model inheritance that does not come from TypeScript’s built-in classes. (In my case, I’m talking about Dojo, but most JS libraries have some utility method for subclassing at this point.) This is important at least until TypeScript’s inheritance system can match the features of other more advanced systems (e.g. mixins/traits). I don’t want to have to use TypeScript’s system and lose multi-inheritance; I don’t want to have to use a JavaScript library and lose typing; I don’t want to make a hack out of TypeScript that requires me to manually compose the resulting type.

Having looked at issue 1364 which discusses union types, and looking at some of the definitions in DefinitivelyTyped that simply return Any types (like backbone.d.ts), I am not sure if this is related to #1364 or if it should be a new issue so I figured I would post my thoughts here. (I have seen some other threads talking about related concepts but nothing that puts it this plainly; hopefully I did not just miss an identical discussion.)

Given a method that combines two objects, I would like to be able to define the resulting combined type automatically, without needing to explicitly provide a new type that combines all properties from the n other types, like so:
// + indicates a combined type
function extend<T,U>(superclass:T, subclass:U):T+U;

class Model {

// the rest-argument-like syntax is just some crap to
// try to indicate it is an array of different generic types,
// not an array of one type
function decl<T,U>(superclasses:...T[], subclass:U):T+U;

function mixin<T,U>(target:T, ...source:...U[]):T+U;
Does this make any sense? Am I way off base? Should a new issue be opened about this?

Thanks for your input,
Nov 7, 2013 at 7:20 PM
This seems to me like you want any future union types to work correctly over generics yes? The second thing you do with rest param syntax and generics seems better accomplished by a constraint on the generic type that is the base type of all the array elements.
Nov 7, 2013 at 7:51 PM
Well, the thing is that there is no “generic base type” for all the array elements being passed. Let me try explaining better by example.

Creating a constructor for a data grid component, with modules to add keyboard navigation support and row selection support, would be declared like this: var CustomGrid = decl([ OnDemandGrid, Keyboard, Selection ], { someCustomProperty: true });.

OnDemandGrid is the primary superclass, Keyboard is a mixin that adds keyMap, pageSkip, addKeyHandler, focus, etc. properties, and Selection is a mixin that adds selection, selectionMode, allowTextSelection, select, etc. properties. The subclass object adds an additional someCustomProperty property that exists only on instances of the newly created type.

I would like to be able to make it so TypeScript knows that CustomGrid is a combination, not an exclusive subset, of the types of OnDemandGrid, Keyboard, Selection, and the anonymous “subclass” type, without needing to laboriously create a new anonymous type myself that includes all the properties of all the mixins. It is my understanding that this is different from a classical “union type” which is one of several possible types, but only one of them at a time. In this case, the resulting type is a combination of all types at the same time.

Does this make more sense?
Feb 1, 2014 at 12:33 PM
This is exactly the missing feature I have hit right now in typescript. I think this is much cleaner solution to the mixin 'problem', it gives the ability to define a mixin method without forcing mixins to be a first class concept that some other suggestions require.

Was there any more TypeScript developer thoughts on this language extensions?