"dynamic" keyword for classes/variables

Topics: Language Specification
Apr 24, 2013 at 7:14 PM
Have there been any discussions on supporting a "dynamic" keyword for classes or variables? Seems like this would be a big help in transitioning from existing JS codebases.

As an example using the jquery.d.ts from DefinitelyTyped, one could simply add dynamic to the $ declaration as such:
declare dynamic var $: JQueryStatic
This would then allow the compiler to know that $ may be extended with other methods/properties besides those that were defined on the JQueryStatic interface - as is common when working with jQuery plugins.

Code completion could continue to work for everything that was defined in the interface, but the compiler wouldn't complain about other usages.

It's nice that there are declaration files for all the common libs, but for an internal codebase with existing JS "classes", having to write the declarations to pull them into the TS fold becomes a pretty big task. I know they can still be used via manual JS, but (as far as I know) we're not able to take advantage of the additional TypeScript features like "extends" or super() and call some class-specific methods without having the full declarations in place.

It'd be great to be able to get the ball rolling with a minimal declaration like so:
// in .d.ts
declare module "existingFile" {
  export class dynamic class ExistingClass {}
}

// in .ts
import m = module("existingFile");
class NewClass extends m.ExistingClass {
  // ...
}
Coordinator
Apr 25, 2013 at 4:18 PM
More generally, we've talked about ways of supporting expand, though no conclusions there, yet. I agree that it's common to start at some known structure and grow a little from there. We can at least know the documented starting point.

Probably not going to try to tackle this before 1.0, but it might be worth coming back to after 1.0.
Apr 30, 2013 at 6:54 AM
Edited May 21, 2013 at 11:18 AM
Something along the lines of that would help out considerably, especially with porting existing code bases, there is still far to many errors thrown by typescript due to the way it tries to infer types... "expandable" should be the default for non explicitly declared variables in my opinion. cases like these are common in many JS codebases but not supported by Typescript, unless you explicitly declare things any, where the idea of porting existing code bases drops dead instantly.
//Common practice in Angular, but mixed arrays are properly more widely spread than we expect.
var mixedArray = ['something', function(something) {}];

//This I have seen so many places, so that is just so extremely common practice, and it's silly for TS not to support it.
var exp = {};
exp.ideally = "this";
exp.should = "work";


function getValue() {
  if(iHaveValue)
    return value;
    //Just a simple value -> string/int/object
  else
    return http.get("/value"); 
    // Promise that resolves to a value, normally I wouldn't wan't to mix the return types,
    // but for Promises/values when a framework like angular directly supports this, wrapping
    // the above in a promise becomes boilerplate, besides promises are a special case scenario for mixed return types.
    // In any case, this could be a very disputed thing to do even with promises,
    //
    // it is still a conflict with JS and should just warn, where users could then configure the compiler to warnings as errors,
    // ideally where warning types could be ignored individually by configuration and/or level of severity.
}

May 2, 2013 at 7:03 PM
Besides allowing module.exports, I think this is the biggest issue with adopting TypeScript for existing projects.

For variables, you can at least use "any" and keep moving, but for existing "classes" you're pretty much out of luck unless you write a d.ts file to go along with it.


Using the inheritance example from the TypeScript playground, assuming I had the following Animal class already in Javascript:
// animal.js (copied from output of TypeScript playground example)
var Animal = (function () {
    function Animal(name) {
        this.name = name;
    }
    Animal.prototype.move = function (meters) {
        alert(this.name + " moved " + meters + "m.");
    };
    return Animal;
})();
I can't do
// snake.ts (copied from TypeScript playground example)
class Snake extends Animal {
    constructor(name: string) { super(name); }
    move() {
        alert("Slithering...");
        super.move(5);
    }
}
without also writing a new d.ts and then referencing that in snake.ts.
// animal.d.ts
class Animal {
    public name: string;
    constructor(name: string);
    public move(meters: number): void;
}
In this simple example, I've already doubled the amount of work to create my new Snake class.
May 2, 2013 at 7:22 PM
Another help would be to allow a "Class" type - which by default would be assumed dynamic.
This would alleviate the need to have a d.ts altogether, as well as the reference tag in the .ts
// snake.ts
var Animal: Class = require('animal.js');
class Snake extends Animal {
    // ...
}
Granted, it would prevent a lot of compiler errors that would be caught with the full declaration, but we're still better off with the added code completion from TypeScript. More importantly, it eliminates the friction between JS/TS and lets the codebase start moving in the right direction with TypeScript immediately.