Overloading on constants is the most interesting of the three and is one of the unique features of TypeScript. It allows for precise type annotations on functions that return different objects based on the value of an argument. The definitive example is
document.createElement
:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
inteface Document { | |
createElement(elementName: string): HTMLElement; | |
createElement(elementName: 'audio'): HTMLAudioElement; | |
createElement(elementName: 'canvas'): HTMLCanvasElement; | |
// ... | |
} |
This not only saves us the annoying cast in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var audio = <HTMLAudioElement>document.createElement('audio'); | |
// becomes | |
var audio = document.createElement('audio'); |
But also catches the next typo at compile time if we are more a little bit more explicit about the type:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var audio:HTMLAudioElement = document.createElement('adio'); |
Declaration merging allows to split declaration of module or an interface in multiple files. Although it doesn't sound very impressive, the other features would be less convenient to use with Coherent UI API without it.
Generics have no surprises and work as most other languages. They allow for type safe declaration of containers and generic functions. We are going to use them for type safe declaration of promises:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Callback<T> { | |
(result: T):any; | |
} | |
interface Promise<T> { | |
then(success: Callback<T>, error?: Callback<T>): Promise<any>; | |
success(callback: Callback<T>, context?: any): Promise<any>; | |
always(callback: Callback<T>, context?: any): Promise<any>; | |
otherwise(callback: Callback<T>, context?: any): Promise<any>; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///<reference path="coherent.d.ts" /> | |
// using declaration merging to add overloads for 'on' and 'call' | |
interface Engine { | |
on(name: 'showUnit', callback: SingleArgumentCallback<Unit>): EventHandle; | |
call(name: 'getAbilities', unitId: number): Promise<Ability[]>; | |
} | |
interface Unit { | |
id: number; | |
} | |
interface Ability { | |
name: string; | |
level: number; | |
} | |
class UnitAbilities { | |
constructor(unit: Unit) { | |
this._unit = unit; | |
} | |
public show(): void { | |
engine.call('getAbilities', this._unit.id).then(abilities => { | |
// abilities are array of Ability instances | |
this.render(abilities); | |
}); | |
} | |
private render(abilities: Ability[]): void { | |
} | |
private _unit: Unit; | |
} | |
engine.on('showUnit', unit => { | |
// unit implements the Unit interface | |
var abilitities = new UnitAbilities(unit); | |
abilitities.show(); | |
}); |
engine.call
method.Given the above declarations I would hope the following code to generate a compile-time error about
Show
having wrong signature:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Show(x:number) { | |
} | |
engine.on('showUnit', Show); |
"Because string literal types are subtypes of the String primitive type, when a function call argument matches a parameter of a string literal type in a specialized signature, the overload resolution rules (section 4.12.1) give preference to that signature over a similar signature with a regular string parameter."
This means that if the second argument is not of a type matching the overload declaration, the declaration is simply ignored and the code is perfectly valid.
TypeScript gets better and better and is used in more projects. Most JavaScript libraries have type declarations either bundled or in projects like DefinitelyTyped, making TypeScript valuable even for smaller projects that just glue some third-party libraries.
So if want to use TypeScript for your game user interface the place to start is the type declarations for coherent.js
No comments:
Post a Comment