• No constraints
  • Cannot do any lookups on T, cannot assign anything other than any to T, cannot assign T to anything other than any and T ("T is a branded {}")
  • Function expressions cannot declare generic parameters
  • Class methods, function declarations
    • Later: What about object literals?

What's left:
  • Inference
    • Would like: Infer class type parameters from constructor calls
  • Type compatibility
    • Maybe: any's can fill in for T?
  • Try this out for 5 libraries


Generics recap:
  • Type parameters on:
    • Interfaces
    • Classes
    • Functions (some debate, but let's assume all)
  • No constraints
  • Type parameter type: like a fresh {}
    • (<T>x). Shows Object members
    • null, undefined and any assignable to T
  • Assignment and subtyping
  • Function signatures can have type params
  • Type argument inference

var f: {
  <T>(t1: T, t2: T): void;

var g: {
  <T,U>(t1: T, t2: U): void;

var h: {
  (t1: any, t2: any): void

f = g;  // ok
g = f;  // error
f = h; // ok
h = f; // ok
g = h; // ok
h = g; // ok

  • Error to have a type parameter on a function signature which is
  • Inference

foo<T>(x: T): T {… }
foo(5) // should infer foo<number>(5)

Goal is to rarely have to say the type arguments
class List<T> {
   first: T;
   getAt(i: number): T
   setAt(i: number, v: T): void;

map<T,U>(items: List<T>, mapper: (item: T) => U): List<U>
var foos = new List<Customer>();
var names = map(foos, x => x.name);

Part 1: match foos with List<T> and make a bunch of inferences for T. Then run best common type on these and use result or error.

Part 2: Idea:
  1. Each argument expression has a list of type parameters it depends on
  2. In left to right order, when you get to an argument expression that depends on type parameters, lock down those parameters based on all inferense so far, and keep going.

Inference of generic parameters is fully separate from overload resolution.

f<T>(t1: T, t2: T)
f<t,U>(t: T, t2: U)

Follow same sort of rule as:
var f : {
	(x: number): number;
	(x: number, options?: any): string;

var z = f(5)

Q: Are there really any uses for method-level type parameters only in return position?

Later topic: Contextual typing: var x: number = bar();

Type arguments and constructors:

class List<T> {
  constructor(defaultItem: T) {…}

var List:{
  new <T>(defaultItem: T): List<T>

Things that you can't do here:
- Flatten<T> below

flatten<T>(this: List<List<T>>): List<T>;


/////////  PROMISE /////////////
// As discussed in design meeting
//  (1) we don't yet know of any cases where this fails
//  (2) seems we need the four overloads of then to deal with success or failure being T 
or Promise<T>
//  (3) progress should be added
interface Promise<T> {
  then<U>(success?: (x: T) => U, failure?: (x: any) => U): Promise<U>;
  then<U>(success?: (x: T) => U, failure?: (x: any) => Promise<U>): Promise<U>;
  then<U>(success?: (x: T) => Promise<U>, failure?: (x: any) => U): Promise<U>;
  then<U>(success?: (x: T) => Promise<U>, failure?: (x: any) => Promise<U>): Promise<U>;
  done(success?: (x: T) => any, failure? (x: any) => any): void;

var p = {
  then(success?: (x: string) => any): any;
/////////  WINRT /////////////
// Basic:  
//  (1) just a handful of generic types
//  (2) no generic methods
interface Windows.Foundation.Collections.IIterable<T> {
    first(): Windows.Foundation.Collections.IIterator<T>
interface Windows.Foundation.Collections.IIterator<T> {
    current: T;
    hasCurrent: bool;
    moveNext(): bool;
    getMany(): T[];
interface Windows.Foundation.Collections.IVector<T> extends T[] {
    size: number;
    getAt(index: number): T;
    indexOf(value: T): { index: number; returnValue: bool; };
    getMany(startIndex: number): T[];
    setAt(index: number, value: T): void;
    insertAt(index: number, value: T): void;
    removeAt(index: number): void;
    removeAtEnd(): void;
    clear(): void;
    replaceAll(items: T[]): void;
interface Windows.Foundation.Collections.IMapView<K,V> {
    size: number;
    lookup(key: K): V;
    hasKey(key: K): bool;
interface Windows.Foundation.Collections.IMap<K,V> {
    size: number;
    lookup(key: K): V;
    hasKey(key: K): bool;
    getView(): Windows.Foundation.Collections.IMapView<K,V>;
    insert(key: K, value: V): bool;
    remove(key: K): void;
    clear(): void;
/////////  ES6 Iterators /////////////
interface Iterator<T> {
  next(): T;
interface Iterable<T> {
  iterator(): Iterator<T>;
// This guy is hard
interface Generator<T> extends Iterator<any> {
    send(x: any): any;
var f: () => Generator<string> = function *() {
    var data = yield $.ajax(url);
    var status = $('#status').html('Download complete.');
    yield status.fadeIn().promise();
    yield sleep(2000);
    return "hello";
var p: Promise<string> = spawn(f);
/////////  KNOCKOUT /////////////
// (1) Generic "Observable" interface the central object of KnockOut
// (2) Nice interaction of generics and interface call signatures
// (3) Interesting need for 'generic this' for chaining of sets
declare module ko {
    export interface Observable<T> {
        (): T;
        (value: T): void; 
        <O>(this: O, value: T): O; // Is this legit?
        subscribe((newValue: T) => void ): {
        dispose(): void
    export function observable<T>(value: T): Observable<T>;
    export function applyBindings(viewModel: any): void;
    export function computed<T>(() => T, owner: any): Observable<T>;
    export function computed<T>({ read: () => T; write?: (value: T) => void; owner?: any}): Observable<T>;
    export function isComputed(o: any): bool;
    export function isObservable(o: any): bool;
    export function observable(o: any): bool;

var o = {
   x: ko.observable("hello"),
   y: ko.observable(5),
   z: ko.computed(function() {
      return this.x + this.y; 

/////////  UNDERSCORE /////////////
// Looks to be fairly standard LINQ-like library from the generics standpoint
// (1) Iteration over both arrays and objects (ordered string keyd dictionaries)
// (2) Not yet modelled below - API allows chained mode _([1,2,3]).map(f).filter(g)

_.each({a: 1, b: 4}, function(n) { return n + 1; });
// Note: 

interface Underscore {
          list: T[],
          iterator: (element: T, index: number, list: T[]) => any,
          context?: any): void;
          obj: {[x: string]: T},
          iterator: (value: T, key: string, object: {[x: string]: T}) => any,
          context?: any): void;
     map<T, U>(
          list: T[],
          iterator: (element: T, index?: number, list?: T[]) => U,
          context?: any): U[];
     map<T, U>(
          obj: {[x: string]: T},
          iterator: (value: T, key?: string, object?: {[x: string]: T}) => U,
          context?: any): U[];
    invoke(list: any[], methodName: string, ...arguments: any[]): void;
    pluck<T,U>(list: T[], propertyName: string): U[];
    max(list: number[]): number;
          list: T[],
          iterator: (element: T, index: number, list: T[]) => number,
          context?: any): number;
          list: T[],
          iterator: (element: T, index: number, list: T[]) => string,
          context?: any): { [key: string]: T[]; };

_.groupBy([1,2,3, 19], function(x) { return x.toString()[0]; })

{"1": [1,19], "2": [2], "3": [3] }

(<number[]>_.pluck(["a","b","c"], "length")) => [1,1,1]
_.pluck<string, number>(["a","b","c"], "length") => [1,1,1]


Generics and constraints.

Today: foo(x: Comparable): Comparable {}
Generics: foo<TComparable>(x: TComparable): TComparable {}

Without constraints, the generic version is less expressive than the non-generic version (and as such, less useful in .d.ts to check against interface contracts). To regain this expressivity, we need to allow for constraints. Constraints can be based on a type variable extending an interface.

interface Bar {}  //or class Bar {}
class Foo<T extends Bar, U /* extends {} */, V extends Bar> {
  f() {
    var x: T;
    var y: Bar;
    y = x;
    x = y; // error

   var z: V; 
    x = z; // error

function foo<T extends Comparable>(x: T): T {

var myComparable: MyComparable;
var z /* : MyComparable */ = foo(myComparable);

var foo: <T extends Comparable>(x: T) => T;

Interface Collection<T> {
  map: <U>(f: T=>U): Collection<U>;

var myColl: Collection<Foo> = {
  map: function(f) {

Last edited Jan 4, 2013 at 7:12 PM by jonturner, version 6


No comments yet.