Known breaking changes between 0.9.5 and 0.9.7

The ‘noimplicitany’ option now warns on the use of the hidden default indexer

Description: With 0.9.7, we have fixed a bug in the use of ‘noimplicitany’ and indexers, where implicit anys were not being correctly warned in prior versions.

In the following example, any use of an index aside from the known ‘abc’ property will be warned with ‘noimplictany’:

var x = { abc: 1 };
x["abc"];
x[0];     // warning: implicit any
x["def"]; // warning: implicit any


This is because there is no annotation from the user that tells us they wish to allow this kind of arbitrary indexing, where the compiler can’t confirm that these properties exist via the type system. Similarly, indexing through an expression of the string type is warned:

var x = { abc: 1 };
var idx = "abc";
x[idx];   // warning: implicit any


Even though, by inspection, we can see that the ‘idx’ variable is set to the “abc” string constant, this information is not tracked by the compiler. Instead, idx is seen as any string, so the compiler warns it cannot confirm that this string names one of the known properties. As a result, it will type what comes out of the indexing expression implicitly with an ‘any’ type.

Reason: Prior to 0.9.7, users could introduce ‘any’ types implicitly by indexing into objects using arbitrary string values. As JavaScript practices like this are ones that the ‘noimplicitany’ flag help to detect so that the programmer can annotate the types, indexing with arbitrary string values now gives a warning to help the user detect and annotate the expression.

Mitigation: To mitigate this change in existing code bases, you can use one of the following workarounds. As the key point here is that the compiler is having to imply an ‘any’ type because there is no indexer present, you can provide this indexer:

var x: { [index: string]: number; } = { abc: 1 };
var idx = "abc";
x["abc"];
x[idx];   // no longer warns
x[0];     // no longer warns
x["def"]; // no longer warns


The other scenario that is affected is the use of arbitrary string indexing into enumerated values. Just as before, the use of an arbitrary string value will trigger the ‘noimplicitany’ warning:

enum Color { Red, Green, Blue };
var redString = "Red";
var redEnumVal = Color[redString]; // warning: implicit any


Here are two additional workarounds for enums, as they are treated specially with regards to indexing.

The first is to explicitly handle the typing of the indexing expression:

enum Color { Red, Green, Blue };
var redString = "Red";
var redEnumVal: Color = (<any>Color)[redString]; // no longer warns


If the use of indexing of enums is more prevalent in an area of code, it may be more helpful to use an intermediary value that provides this indexer:

enum Color { Red, Green, Blue };
var redString = "Red";
var Color2: { [idx: string]: Color; } = <any>Color;

var redEnumVal2 = Color2[redString];

Generic constraints no longer can reference parameters in the same parameter list

Description: In our continued efforts to simplify the language, we're simplifying what generic constraints can entail.

An example like this is now an error:
interface Service<T> {
    service(t: T): T;
}

//Error: Service<T> references T, which is a type parameter in the same list
function f<T extends Service<T>>(x: T) { }

//Likewise. Error: Service<U> references U, which is a type parameter in the same list
function g<U, T extends Service<U>>(x: T) { }


Instead, use constraint arguments that are not in the same argument list, make constraints non-generic, or simply pass 'any' as the parameter to the constraint.

Reason: The added overhead in terms of type-checking, error-reporting, and design complexity did not add enough additional expressiveness to make it worthwhile for 1.0. We may revisit this in future versions of TypeScript.

Interfaces now merge with later interfaces having a higher priority

Description: With 0.9.5, we simplified the overload resolution algorithm. In this new algorithm, overloads are tried starting at the top overload, proceeding through each overload looking for a match. The first match wins.

This rule extended to interface merges that merged their overload sets. The overloads for an earlier interface would have precedence over those from a later merged interface. This made it difficult to extend the overload set of built-in types (those in lib.d.ts), as well as model the “plugin” architecture of libraries like jQuery.

This change will reverse the order interfaces merge overload sets, so that when interface A is merged with a later declaration of interface A (here called interface B to disambiguate), the overload sets of B will get precedence.

Example:
interface I {
   foo(x: number): void;
   foo(x: string): void;
}
interface I {
   foo(x: Date): void;
   foo(x: {abc: string}): void;
}

Will be treated, after merged, as the type:
interface I {
   foo(x: Date): void;
   foo(x: {abc: string}): void;
   foo(x: number): void;
   foo(x: string): void;
}

Notice that the overloads in each set themselves do not reverse order, rather the sets are treated as a single unit, and these units are merged in the reverse order.

Reason: The previous order made it difficult to work with built-in types (those in lib.d.ts), as users would have had to manually managed when lib.d.ts was referenced in their projects. Additionally, using jQuery “plugins”, users would have had to include the plugin before base jQuery library, which is unintuitive and cumbersome to manage.

Known breaking changes between 0.9.1 and 0.9.5

Default type for type arguments is {} not any

Description: Previously, if a type argument was inferred, but had no candidates, its type would go to 'any'. We now infer '{}' in the cases of no inference candidates.
Reason: Inferring 'any' when there are no candidates allowed the 'any' type to leak out into surrounding expressions, effectively turning off type checking when no candidates were involved. The much closer approximation was what is inferred for the type variable inside of the function, namely '{}'.

The explicit indexer for Object has been removed

Description: As part of the effort to allow developers to get more benefit out of "no implicit any", the indexer on the Object has been removed. This will make any use of the implied indexer on an object a warning under "no implicit any".

This has an impact on code that uses the indexer as part of the type, as in this example:

function useEnum(e: { [idx: string]: any}) {
    return e["test"];
}

enum Colors { Blue, Green, Orange }

useEnum(Colors);  //errors in 0.9.5, but has no error in 0.9.1.1

Reason: This comes from the work to allow developers to tighten the type coverage in their code.

The 'any' type is now properly disallowed from being the subtype of {}

Description: The breaking change here is that any is not a subtype of {} anymore. This would break code like the following:
interface MyOptionals {
    optional1?: number;
    optional2?: boolean;
}

interface MyInterface {
    call(): MyOptionals;
} 

// MyClass does not implement MyInterface 
class MyClass implements MyInterface { 
    call(): any {
        return null;
    }
}

The issue here is that we used to incorrectly treat “any” as a subtype of MyOptional, or any object type with no required properties.

Reason: This was unintentionally allowing subclasses and interface implementer to not follow the specified type contract when specific types are required.

Overload resolution rules simplified

Description: Overload resolution now follows a much simpler algorithm. When multiple overloads fit for a given call, we pick the first fit rather than the trying to find the "best fit".

This means that code with overloads should now be manually sorted from the tightest/more-specific overload to loosest. The one exception is that an 'any' in the callee will try to match an 'any' in the caller. For example:

interface Parent { x; }
interface Child extends Parent { y; }

function f(p: Child): Child;
function f(p: Parent): Parent;
function f(p: any): any;
function f(p: any) { return p; }

var a = f({ x: 3, y: 4}); // a: Child
var b = f({ x: 5 }); // b: Parent

var y: any;
var c = f(y); // c: any


Reason: This greatly simplifies reasoning about the overload during function resolution and more closely matches what the underlying JavaScript logic would be performing.

Rest arguments are now properly checked for function arity

Description: You will need to properly handle functions with rest args as if they could have 0 or 1 arguments in the position of the rest arg. For example:

function myFunction(f: (...args: string[]) => void) { }

myFunction((x, y) => { }); //0.9.1.1
myFunction((x?, y?) => { }); //0.9.5

Reason: The compiler was unintentionally too lenient in this case and allowed errors where functions were mismatched. We have tightened it to prevent these issues.

Parsing rules for arrow functions require parens if the lambda is immediately called

Description: We've fixed the parsing rules of lambda functions to better align with ES6. In ES6, if lambda is immediately invoked, you need to put parentheses around the lambda, as in this example:

var f1 = () => { return 5 }();  // Error now, used to be OK in 0.9.1.1
var f2 = (() => { return 5 })(); // OK in 0.9.1.1 and 0.9.5

Reason: This aligns with the ES6 language spec

Can not declare external modules inside other external modules

Description: It used to be possible to declare new external modules from inside an external module, though this is confusing as external modules can only be declared at global/top-level scope. We have changed this to require declaring external modules to be declared only at top-level. For existing code, this would mean moving the declare module to a .d.ts file and referencing it from the external module.
Reason: Simplifies reasoning about the scopes that symbols are declared in.

Change: Disallow --noResolve and import declaration of the external module reference

Description: We now disallow commandline parameters that interact poorly from being used together. Specifically, --noResolve and external modules can not be used together as resolving the external module is required during codegen.
Reason: External modules need to be resolved for correct codegen

Known breaking changes between 0.9 and 0.9.1

Clean up of commandline options

Description: There was a mix of commandline options, some that were no longer maintained and weren't expected to work correctly. With this, we have done a clean-up of the options so that we provide supported options that can be maintained going forward. Specific changes: --out has been split into --out for filenames and --outDir for directories and some casing changes to make the options more uniform. The --comments option has also been replaced with its opposite, --removeComments, as we now default to preserving the code closely to the original.

Another change is that the module loader style no longer defaults to CommonJS. This is to help users new to TypeScript get a helpful message when creating external modules accidentally (while likely trying to do something else). Options for both CommonJS and AMD are still supported, but must be explicitly passed to the compiler.

Reason: This is more of a general clean-up to get us in shape for 1.0 with commandline options.

In Visual Studio, all TypeScript files in a project are considered to be referencing each other

Description: Previously, all TypeScript files in a project had to reference each other explicitly. With 0.9.1, they now implicitly reference all other TypeScript files in the project. For existing projects that fit multiple projects into a single projects, these will now have to be separate projects.

Reason: This greatly simplifies using TypeScript in the project context.

Known breaking changes between 0.8 and 0.9

The 0.9.x series introduces breaking changes to help the language mature, align with the ECMAScript 5 standard and ECMAScript 6 draft recommendations, and general alignment of the compiler with the spec itself. While we try to limit the number of breaking changes, it’s important to make necessary changes now, before the language and tools reach 1.0.

Below is the list of currently known breaking changes.

Tightening of compiler to spec

Description: There was functionality allowed by the 0.8.3 compiler that was not explicitly allowed by the spec (eg, exploiting patterns of access modifiers to simulate ‘protected’).
Reason: We tightened the compiler to follow the spec more closely to avoid code that relies on a “loose” compiler implementation.

The type ‘bool’ is now ‘boolean’

Description: The name of the Boolean type was initially ‘bool’. During 0.9.0, ‘bool’ will be marked as deprecated, preferring instead the name ‘boolean’. As of 0.9.1, ‘bool’ will no longer be accepted.
Reason: The official name for the Boolean type in ECMAScript is ‘boolean’. The ‘bool’ type name is being changed to align with the standard, based on user feedback.

Default values and optional notation redundant

Description: We no longer allow both having an optional parameter with a default value. Now, you can use the optional parameter when it does not have a default value, otherwise set the default value.

function f(defValue = 3) { }
function f(optValue?:any) { }

Reason: Simplifying syntax to be clear which of the two the user intended.

Syntax of external module imports now uses 'require'

Description: Previously, an external module could be imported using the syntax "import Utils = module('utils')". This is now "import Utils = require('utils')". This is simple syntactic change.
Reason: The 'require' syntax aligns more closely with the code used in both AMD and CommonJS. With "export =" in TypeScript 0.9, this also makes clear that the result of an import may not be a module object.

The ‘module’ keyword no longer creates a type

Description: In 0.9.0, a clearer distinction is made between roles of namespaces, types, and values. Modules now contribute only to namespaces and values and will no longer contribute a type.
Reason: This simplification of the role of modules allow modules to now extend classes and functions more easily.

Introduction of generic types – Change to ‘Array’ type

Description: In 0.9.0, with the introduction of generics, the type of Array is now generic.
Reason: The Array type was less specialized before. Now, with the advent of generics, we can allow for a more precise typing of Array contents.

Introduction of generic types – Change to syntax parsing

Description: In 0.9.0, with the introduction of generics, a difference in how syntax is parsed was introduced. This may affect some forms of syntax that previously parsed as acceptable ES5. Specifically, the following example will no longer be parsed as a comma-delimited expression of two comparisons, but instead as an invocation of a generic function with two arguments:

myfun<x,y>(z)


To make this unambiguously an expression, use parentheses. For example:

(myfun < x), y > (z)


Reason: We follow the precedence set by other languages with regards to syntax for generics. Unfortunately, this does lead to ambiguities in a few cases.

Overload declarations must immediately precede implementation

Description: The 0.8.x series was more lax about what was allowed between overload declaration and its implementation
Reason: Tightening compiler to align with grammar

Indexers must have full type annotation now

Description:
interface a1 {
    [n: number];  //<-- was allowed in 0.8.x, now an error
}
interface a1 {
    [n: number]: string;  //<-- correctly specifies return type, valid in 0.8.x and 0.9.x
}

Reason: Tightening compiler to align with grammar

Statics must be fully-qualified

Description: Previously you could optionally not qualify a static member access when inside a static member definition
Reason: Just as classes require “this.”, statics will require “<Class name>.” to denote where the symbol comes from

No longer accept semicolon at the end of methods

Description:
class Todo extends Backbone.Model {
 
    // Default attributes for the todo.
    defaults() {
        return {
            content: "empty todo...",
            done: false
        }
    };
}

Reason: This may be from following the syntax more strictly in the 0.9.0 fidelity parser. We may soften this restriction in the future.

No longer accept "new number[]"

Description: In the 0.8.x series, we allowed some exceptions to the rule that an expression should follow 'new'. Here we allowed the type "number[]" to follow new.
Reason: This was accidentally allowed in the 0.8.x compiler. As part of the 0.9.x work, we're tightening the compiler, and in doing so no longer allow this.

'declare' now required for top level non-interface declarations in .d.ts files

Description: The 0.8.x series had a lot of lenience in the .d.ts file syntax. We want to tighten the syntax.
Reason: Loose syntax rules are confusing to users and lead to inconsistent .d.ts files.

The node.d.ts distributed with 0.8 is not compatible with 0.9

Description: The 'node.d.ts' distributed as part of 0.8 samples is no longer compatible. Use the up-to-date node.d.ts distributed with the 0.9 samples.
Reason: This is an effect of the "modules no longer create a type" simplification

String indexers constrain the types of members on the interface

Description: A string indexer with element type Foo is a constraint that all members of the interface will have types compatible with Foo. The only exception is that members implicitly inherited from Object which can be called on any object type continue to have the type provided in Object unless explicitly overridden. So this:
    export interface IEventListenerMap {
        hasOwnProperty(eventName: string): bool;
        [eventName: string]: IEventCallback[];
    }

Can be changed to this without changes to consumers of the interface (that is, they can keep using .hasOwnProperty).
    export interface IEventListenerMap {
        [eventName: string]: IEventCallback[];
    }

Reason: String indexers are unified with property lookup in 0.9, so that foo.bar and foo["bar"] behave the same.

Missing "no implicit any" style option

Description: There was an unsupported style option that would error if the compiler had to imply that the type of an expression was 'any'. This generally allowed users to tighten their codebases and only work with typed code.
Reason: This was temporarily removed in 0.9 as part of the refactoring work. We expect to add it back in 0.9.1.

Triple slash references must be listed first

Description: Triple slash references (eg ///<reference path='node.d.ts'/>) must be grouped at the top of the file
Reason: This may be part of the general tightening we did as part of the 0.9 rewrite

Last edited Feb 11 at 5:25 PM by jonturner, version 38

Comments

jmoeller Mar 17 at 6:21 PM 
Regarding "Generic constraints no longer can reference parameters in the same parameter list": Any chance this will come back for 1.0? We are using this feature (which, if I understand it correctly, was already working?) quite extensively in our code base. While the pattern is probably not necessary for simple use cases, it is really useful to have when you are using patterns like mix in and is quite common when using generics as a design approach (instead of just employing it for typesafe collections)

jonturner Jan 8 at 11:23 PM 
@johnny_reilly - that's right, using that file lets you control order. On the commandline, you can also use the ///<reference path=...> compiler hints in your code to specify order.

johnny_reilly Dec 20, 2013 at 8:18 AM 
Hi Guys,

Just noticed the "Interfaces now merge with later interfaces having a higher priority" section under "Known breaking changes between 0.9.5 and 1.0".

It's not stated but I assume that this requires that enforce interface order using _references.ts? I don't know how script ordering is determined in the absence of _references.ts?

bmantuano Sep 5, 2013 at 5:54 PM 
Regarding the "Triple slash references must be listed first" breaking change, is there any plan to allow this moving forward?

From a code organization standpoint, it's much cleaner to keep the amd dependency tags inline with the actual require.js call like so:
var $ = require('jquery'); /// <amd-dependency path="jquery"/>

Rather than in multiple places as is now required:
/// <amd-dependency path="jquery"/>
// ...
// ...
var $ = require('jquery');

Mandating that they be split will be an ongoing maintenance problem.

andykscodeplex Aug 11, 2013 at 12:02 PM 
Could you please elaborate on: 'In Visual Studio, all TypeScript files in a project are considered to be referencing each other ...'

I took this to mean that I don't need to use "/// <reference path= ... " but clearly from the huge number of errors arising when I do this I have got this very wrong.

jonturner Jun 25, 2013 at 5:56 PM 
@jantrum - you can still describe the type that the module provides by hand using interfaces. We're also looking into a way of getting to the module's shape using a 'typeof' keyword in a type position, but this functionality isn't yet in 0.9

omidkrad Jun 3, 2013 at 4:42 PM 
You may want to add this as breaking change:
All tripple slash references should appear at top of the source file, otherwise they will be ignored.
https://typescript.codeplex.com/workitem/1091

Jantrim May 22, 2013 at 4:23 PM 
I am having issues with "modules no longer create a type". Maybe i am forgetting something. But using require http://requirejs.org/docs/api.html modules can be defined as a function, object. How should this be handled in 0.0.9,


in 0.0.8 we could do a

declare module "jquery" {
export function (string selector): jquery;
}

this now results in a compiler error TS1003: Identifier expected

Probably workitems issues https://typescript.codeplex.com/workitem/1029 and https://typescript.codeplex.com/workitem/1058 are related to this problem.

dlshryock May 20, 2013 at 2:52 PM 
@mihailik

Thanks, I'm actually aware that you can use lambdas like that, my hope was to get the ability to use functions like that as well.

Lambdas stored in a var cause a few problems in my opinion: they don't work for inheritance, they're mutable so they can be changed, they can have order of initialization problems, and they don't contain any sort of name property to identify them, which is bad for call stacks, and metaprogramming.

I really like the use of short functions that return their results immediately. For me, limiting yourself to a single computational result for a function is a great way to increase the modularity, and composability of your functions. It gets even better when you can partially apply functions to set up context, and then invoke them later with the rest of the arguments.

I've been using this technique along with the fact that you can extract the name of named functions as a type safe mapping layer between my client and server side code, as well as for handling routing page rendering in the client side. Without the named arrow functions, my code will unfortunately get much longer and more cumbersome.

I'm sure that these things are probably much more of a concern to me than they are to other people, but I figured I'd mention them anyways :D

mihailik May 18, 2013 at 8:50 AM 
Almost precisely that lambda is what's supported today:

var addOne = (n: number) => n+1;
var x: (a,b) => (c,d) => a+b+c+d

class A{
private _name:string;
greeting: () => "Hello, "+name;
}

dlshryock May 17, 2013 at 9:27 PM 
Is there any possibility of returning the ability to write functions like lambdas?

for example, it was to be possible to write the following prior to the 0.9 alpha:

function addOne(n:number) => n+1;

It probably doesn't seem very important for simple cases like the above, but it is extremely useful if you are doing function currying / partial application:

function x(a,b) => (c,d) => a+b+c+d;

would have to become:
function x(a,b){return function(c,d){ return a+b+c+d;} }

a fully curried function:
function x(a) => (b) => (c) => (d) => a+b+c+d;
would have to be:
function(a){return function(b){return function(c){return function(d){ return a+b+c+d; } } } }

It gets worse and worse the more you want to break argument lists apart.

And yes, I am using the arrow functions in real life production application, and would prefer them to be real named functions, not lambda variables :D

I would even like to go so far as to ask for their support as methods:

class A{
private _name:string;
greeting() => "Hello, "+name;
}

NN May 3, 2013 at 5:59 PM 
https://typescript.codeplex.com/releases/view/105503
Here you have installer and specification

marcocenz May 1, 2013 at 9:03 AM 
There is an updated version of the Language specifications?
The only one I've found is of October 2012 for Language version 0.8.0 :-(

omidkrad Apr 29, 2013 at 8:12 PM 
I love these improvements. Specially tightening the .d.ts definitions, it was becoming confusing.

jonturner Apr 23, 2013 at 6:14 PM 
Thanks, oisin. Fixed.

oisin Apr 23, 2013 at 2:11 PM 
You accidentally linked to a new page with your indexer example. It should be:

foo.bar and foo[ "bar" ]