Compiler
Conception
BasicTypes
let isDone: boolean = false;
let binary: number = 0b1010;
let color: string = "blue";
let list: number[] = [1, 2, 3];
// use generic
let list: Array<number> = [1, 2, 3];
// use tupple type
let x: [string, number];
// use enum
enum Color {Red = 1, Green = 2, Blue = 4};
let c: Color = Color.Green;
// any
let notSure: any = 4;
// void
function warnUser(): void {
alert("This is my warning message");
}
// null and undefined
let u: undefined = undefined;
let n: null = null;
let strLength: number = (<string>someValue).length;
let strLength: number = (someValue as string).length;
let strLengths: Array<number> = (Array<number>values).length;
type myDefinedType = string;
type myCreatedType = string[];
const num = <number> numberStringSwap('1234');
const str = numberStringSwap(1234) as string;
// intersection types
interface Foo {
name: string;
count: number;
}
interface Bar {
name: string;
age: number;
}
export type FooBar = Foo & Bar;
// Maped Types
type ToPomise<T> = { [K in typeof T]: Promise<T[K]> };
// Conditional types
type InstanceOfExample = InstanceType<typeof Renderer>; // Renderer
Interface
interface SquareConfig {
label: string;
// ? stands for optional
color?: string;
width?: number;
[propName: string]: any;
(source: string, subString: string): boolean;
cardType: RedCard | BlueCard | GreenCard;
readonly x: number;
readonly y: number;
createCardPicker(this: Deck): () => Card;
}
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
interface Shape { color: string; }
interface PenStroke { penWidth: number; }
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square = <Square>{};
square.color = "blue";
square.sideLength = 10;
square.penWidth = 5.0;
Advanced form:
interface DataConfig {
[reportName: string]: [keyof PerformanceTiming, keyof PerformanceTiming]; // [startEvent, endEvent]
}
Class
class Person {
protected name: string;
protected constructor(theName: string) { this.name = theName; }
}
// Employee can extend Person
class Employee extends Person implements eat, shit, fuck {
static origin = {x: 0, y: 0};
static func = (a: string) => string;
private department: string;
protected protectedFn: () => any;
readonly name: string;
readonly numberOfLegs: number = 8;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
}
else {
console.log("Error: Unauthorized update of employee!");
}
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // Error: The 'Person' constructor is protected
Abstract Class
abstract class Department {
constructor(public name: string) {}
printName(): void {
console.log("Department name: " + this.name);
}
abstract printMeeting(): void; // must be implemented in derived classes
}
class AccountingDepartment extends Department {
constructor() {
super("Accounting and Auditing"); // constructors in derived classes must call super()
}
printMeeting(): void {
console.log("The Accounting Department meets each Monday at 10am.");
}
generateReports(): void {
console.log("Generating accounting reports...");
}
}
let department: Department; // ok to create a reference to an abstract type
department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // error: method doesn't exist on declared abstract type
Functions
// Function returning never must have unreachable end point
function error(message: string): never {
throw new Error(message);
}
function buildName(firstName: string, lastName?: string) {
if (lastName)
return firstName + " " + lastName;
else
return firstName;
}
let result1 = buildName("Bob"); // works correctly now
let result2 = buildName("Bob", "Adams", "Sr."); // error, too many parameters
let result3 = buildName("Bob", "Adams"); // ah, just right
// reset parameters
function buildName(firstName: string, ...restOfName: string[]) {
return firstName + " " + restOfName.join(" ");
}
interface Deck {
suits: string[];
cards: number[];
createCardPicker(this: Deck): () => Card;
}
// a more complex one
export function onDidCreateEditor(listener: (codeEditor: ICodeEditor) => void)
: IDisposable;
export function create(
domElement: HTMLElement,
options?: IEditorConstructionOptions,
override?: IEditorOverrideServices
): IStandaloneCodeEditor;
export function createModel(value: string, language?: string, uri?: Uri): IModel;
We can also describe function with over-loaded type:
declare function getWidget(n: number): Widget;
declare function getWidget(s: string): Widget[];
declare function fn(x: HTMLDivElement): string;
declare function fn(x: HTMLElement): number;
declare function fn(x: any): any;
var myElem: HTMLDivElement;
var x = fn(myElem); // x: string, :)
Generics
In languages like C# and Java, one of the main tools in the toolbox for creating reusable components is generics, that is, being able to create a component that can work over a variety of types rather than a single one. This allows users to consume these components and use their own types.
/**
* Generics Functions
*/
function identity<T>(arg: T): T {
return arg;
}
function loggingIdentity<T>(arg: Array<T>): Array<T> {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
// or in this way
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
/**
* Generics Types
*/
interface Thenable<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(
onfulfilled?: (value: T) => TResult | Thenable<TResult>,
onrejected?: (reason: any) => TResult | Thenable<TResult>
): Thenable<TResult>;
then<TResult>(
onfulfilled?: (value: T) => TResult | Thenable<TResult>,
onrejected?: (reason: any) => void
) : Thenable<TResult>;
}
interface IEvent<T> {
(listener: (e: T) => any, thisArg?: any): IDisposable;
}
export class Emitter<T> {
constructor();
readonly event: IEvent<T>;
fire(event?: T): void;
dispose(): void;
}
getProperty
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
return o[name]; // o[name] is of type T[K]
}
Enmu
enum FileAccess {
// constant members
None,
Read = 1 << 1,
Write = 1 << 2,
ReadWrite = Read | Write,
// computed member
G = "123".length
}
export enum DocumentHighlightKind {
/**
* A textual occurrence.
*/
Text = 0,
/**
* Read-access of a symbol, like reading a variable.
*/
Read = 1,
/**
* Write-access of a symbol, like writing to a variable.
*/
Write = 2,
}
Module
Normal Modules:
export * as Validator from "./StringValidator"; // exports interface 'StringValidator'
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
declare let $: JQuery;
export default $;
Module is an independent functional unit as Ambient Modules. To describe the shape of libraries not written in TypeScript, we need to declare the API that the library exposes.
We call declarations that don’t define an implementation “ambient”. Typically, these are defined in .d.ts
files. If you’re familiar with C/C++, you can think of these as .h
files. Let’s look at a few examples.
External Dependencies:
More to say, use /// <reference types="moment" />
to include a global libraries.
declare module "url" {
export interface Url {
protocol?: string;
hostname?: string;
pathname?: string;
}
export function parse(urlStr: string, parseQueryString?, slashesDenoteHost?): Url;
}
declare module "path" {
export function normalize(p: string): string;
export function join(...paths: any[]): string;
export var sep: string;
}
/// <reference path="node.d.ts"/>
/// <reference path="../typings/global.d.ts" />
import * as URL from "url";
let myUrl = URL.parse("http://www.typescriptlang.org");
declare module 'visualEngine' {
export interface engineVersion {
version: string;
}
}
declare module 'monaco.languages.typescript' {
enum ScriptTarget {
ES3 = 0,
ES5 = 1,
ES2015 = 2,
ES2016 = 3,
ES2017 = 4,
ESNext = 5,
Latest = 5,
}
export enum ModuleResolutionKind {
Classic = 1,
NodeJs = 2,
}
type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[];
interface CompilerOptions {
maxNodeModuleJsDepth?: number;
module?: ModuleKind;
moduleResolution?: ModuleResolutionKind;
newLine?: NewLineKind;
noEmit?: boolean;
noEmitHelpers?: boolean;
noEmitOnError?: boolean;
noErrorTruncation?: boolean;
noFallthroughCasesInSwitch?: boolean;
noImplicitAny?: boolean;
noImplicitReturns?: boolean;
rootDirs?: string[];
skipLibCheck?: boolean;
skipDefaultLibCheck?: boolean;
sourceMap?: boolean;
sourceRoot?: string;
strictNullChecks?: boolean;
suppressExcessPropertyErrors?: boolean;
suppressImplicitAnyIndexErrors?: boolean;
target?: ScriptTarget;
traceResolution?: boolean;
types?: string[];
/** Paths used to compute primary types search locations */
typeRoots?: string[];
[option: string]: CompilerOptionsValue | undefined;
}
export interface DiagnosticsOptions {
noSemanticValidation?: boolean;
noSyntaxValidation?: boolean;
}
export interface LanguageServiceDefaults {
/**
* Add an additional source file to the language service. Use this
* for typescript (definition) files that won't be loaded as editor
* document, like `jquery.d.ts`.
*
* @param content The file content
* @param filePath An optional file path
* @returns A disposabled which will remove the file from the
* language service upon disposal.
*/
addExtraLib(content: string, filePath?: string): IDisposable;
/**
* Set TypeScript compiler options.
*/
setCompilerOptions(options: CompilerOptions): void;
/**
* Configure whether syntactic and/or semantic validation should
* be performed
*/
setDiagnosticsOptions(options: DiagnosticsOptions): void;
/**
* Configure when the worker shuts down. By default that is 2mins.
*
* @param value The maximun idle time in milliseconds. Values less than one
* mean never shut down.
*/
setMaximunWorkerIdleTime(value: number): void;
}
export var typescriptDefaults: LanguageServiceDefaults;
export var javascriptDefaults: LanguageServiceDefaults;
export var getTypeScriptWorker: () => monaco.Promise<any>;
export var getJavaScriptWorker: () => monaco.Promise<any>;
}
Declarations
The typescript declarations template files demo.
- Auto generating
index.d.ts
file dts-gen - Export instance
export interface Popups {
init(): void;
}
declare const popups: Popups;
export default popups;
- Export module in global
declare global {
interface Window {
dd: DingTalkGlobal;
}
}
Realtime Practice
Make RE typescript :)
Why TypeScript?
- Problem you want to solve?
- Start to figure out how to solve that sort of problem?
- monaco editor interface.
- Angular 2 strongly support.
- Typescript ~
How to make it possible?
- Static type system like Java, ready for the large project. Module / Class / Function …
- Use interface to rule theme all, clean the mess, reveal the clean and beautiful design of your app. Everything is clear and ready.
- Code Intelligence just like Java but more powerful than Java itself with the core power of JavaScript.
- Purity for module / class / function design. Think and design before writing a byte of code.
Other features:
- Static type check / compiling bugs detect.
- Fake Java. Interfaces / Method modifier / Inheritance / Generalization / Enum (Use Trumps’ Image and PS it)
- Code refactoring and Test Friendly.
Quick Demo
- RE Code declarations. My mom shall never worry about the misunderstanding of the code that people write without attention :)
- Not familiar with the whole architecture.
- Not familiar with methods.
- Not familiar with the data-structure passed through the code.
- Use reference of VE as
ve.d.ts
. Auto completion - Design to make things great.
HistoryPane API Design
.
Summary
- Try Typescript and think in a different way.
- Use typescript for designing your App’s architecture. Draw a big picture of your complex system design just in a Typed System.
- Carefully design and craft those declarations shall be more friendly to a new developer. It is a good way to pay the debts of the future. To control the complexity in a more acceptable range.
Ref
Demo Project
- WetLand ORM. An ORM for Node.js written in typescript. Works with MySQL, PostgreSQL, SQLite and more.
- Monaco Editor’s
.ts
type specification file. - Typescript in JavaScript
- Typescript in Chair
- DefinitelyTyped: make typed
*.d.ts
files.