Typescript is a superset of JavasCript and we can use all the features of ES6 and more.
If we only use ES6 functionality we could also use BabelJS.
- It is a superset of javascript
- strong typing (types add safety)
- advanced language constructs
- compiles to plain old javascript
To use the new features today we can use a Transpiler.
sudo npm install -g tsc
# or
sudo npm i -g typescript
# typescript compiler
tsc -help
ES6-style TypeScript -> Typescript as transpiler -> ES5 Javascript
ES6-style Typescript -> Typescript -> ES6 Javascript -> Babel -> ES5 Javascript
- Hoisting (they are hoisted to the top of the function)
- Functional scope (globally available in the function in which is declared)
- Variable name may be declared a second time in the same function
- Not hoisted
- Block-scoped
- Variable name may only be declared once per block
-
Not hoisted
-
Block-scoped
-
A value MUST be set on const declaration
-
Can't be changed later
-
Can't avoid properties from objects to change* !!!
-
Can't declare class members with const in ES6 (but see namespaces)
-
Works with modules
We can declar const in namespaces, it is not standard in ES6. Only in Typescript.
namespace AtomicNumbers {
export const H = 1;
export const He = 2;
}
namespace Membership {
export function AddMember(name: string) {
// add a new member
}
export namespace Cards {
export function IssueCard(memberNumber: number) {
// issue new Card
}
}
}
Membership.AddMember('Garrett');
Membership.Cards.IssueCard(1234);
- enhances editor support for referenced files
- Typescript compiler will compile all requrired references
- Use -outFile compiler option to generate a single JS output file
/// <reference path="membership.ts" />
You need a triple slash reference in two scenarios:
- When you are referencing JavaScript type definitions e.g. definitions for node, jquery etc. for a great collection see : https://github.com/borisyankov/DefinitelyTyped
- When we want to compile using --out you can reference your files using
/// <reference
.
You need a import/require combo when using external modules i.e. amd/commonjs. If you don't know what these mean (amd/commonjs are javascript terms, not specific to typescript) you don't have to care. Just use /// <reference
and compile with --out.
Update! To help reduce confusion, internal modules are being renamed to “namespaces”. I also advise just as strongly that you avoid mixing namespaces and modules! Thanks to Mike Brocchi for suggesting the update.
Having answered the same question in slightly different forms almost every day this week, I thought it was time to just write an article and hopefully save a lot of time.
TL;DR – TypeScript has internal and external modules. When you write an application, you choose only one of these. You don’t mix them.
Stop mixing TypeScript internal and external modules. They aren’t designed to work together. They are mutually exclusive.
If you are using NodeJS, you don’t even have to choose. You must use external modules – so your code shouldn’t have the “module” keyword anywhere. The file is the module, so you don’t need to write the word “module”. Ever.
In fact, any environment that requires either CommonJS, AMD, or ECMAScript 6 modules is a no-choice environment. You are using external modules. Don’t use the “module” keyword. Seriously. Stop it.
Don’t. If I could go back and re-write my books on TypeScript I would pretend that internal modules didn’t exist. I would take back all those pages and dedicate them to how to use external modules in your web pages, either using an AMD loader like RequireJS, or by running a minifier that crushed them all into a single file before I published them online.
The idea behind internal modules is sound – they represent the most commonly used method in professional JavaScript to keep variables out of the global scope. They reduce the global noise, reduce the chance of collisions, and help you organise you code.
Despite these sound origins, it is better to simply avoid them. External modules are even better at keeping things out of the global scope. They are also better suited to really big applications, by an immense distance.
- Boolean
- Number
- String
- Array
- Enum
- Any
- Void (abscence of a type)
let myString: string = 'this is a string';
myString = 42; // error!!
function ReturnNumber(): number {
return 42;
}
let anotherString: string = 'this is also a string';
anotherString = ReturnNumber(); // error!!
Can be declared two diferent ways (see next code).
let strArray: string[] = ['here','are','strings'];
let strArray2: Array<string> = ['more','strings','here'];
let anyArray: any[] = [42,true,'banana'];
- map
- forEach
- filter/reject
- reduce
- find
- indexOf
enum Category { Biography, Poetry, Fiction }; // 0, 1, 2
enum Category { Biography = 1, Poetry, Fiction } // 1, 2, 3
enum Category { Biogrpaly = 5, Poetry = 8, Fiction = 9}; // 5, 8, 9
let favoriteCategory: Category = Category.Biography;
console.log(favoirteCategory); // 5
let categoryString = Category[favoriteCategory]; // Biography
Array wehre types for first few elements are specified. Types do not have to be the same.
let myTuple: [number, string] = [25, 'truck'];
// Additional elements can be any type from those previously specified
// other elements can have number or strings following the prior declaration
myTuple[2] = 'this works';
TypesScript | JavasCript |
---|---|
Types | No types |
Arrow functions | Arrow functions (ES2015) |
Function types | No function types |
Required and optional parameters | All parameters are optional |
Default parameters | Default parameters (ES2015) |
Rest parameters | Rest parameters (ES2015) |
Overloaded functions | No overloaded functions |
fucntion createCustomerId(name: string: id: number): string {
return name + id;
}
let arr = allBooks.filter(function() {
return book.author === 'Herman Melville';
});
// vs
let arr = allBooks.filter(book => book.author === 'Herman Melville');
- shorthand sytnax for functions
- simplifies the behavior of this
- Value of this is always the containg code
- "Lexical Binding"
- Nested arrow functions share the same this
- No built-in arguments object
- We need to use an ES6 "rest" parameter instead
- Arrow functions aren't new-able
// arrow functions capture the *this* so we don't have to to the usual
// var self = this;
function Book() {
this.publishDate = 2016;
setInterval(() => {
console.log(this.publishDate);
}, 1000);
}
function greet(name) {
return 'Hello, ' + name;
}
// vs
const greet = (name: string) => "Hello, " + name;
This is only a type definition for a function. Do not get confused with arrow functions.
let publishFunc: (someYear: number) => string;
In javascript all parameters are optional, in typescript all are required.
function createCustomer(name: string, age?: number) {}
function getBookByTitle(title: string = 'The C Programming Language') {}
function getBookByTitle2(title: string = getMostPopularBook()) {}
Collects a group of parameters into a single array
function getBooksReadForCust(name:string, ...bookIds: number[]) {}
let books = getBooksReadForCust('Leigh', 2, 5);
let books2 = getBooksReadForCust('Daniel', 2, 5, 12, 42);
- one symbol name
- multiple function types
- one implementation with type guards
// we provied different object definitions but only one implementation
function getTitles(author: string): string[];
function getTitles(available: boolean): string[];
function getTitles(bookProperty: any): string[] {
let foundTitles: string[] = [];
if(typeof bookProperty == 'string') {
// code
}
else if (typeof bookProperty == 'bolean') {
// code
}
return foundTitles;
}
function getTitles(author: string): string[];
function getTitles(available: boolean): string[];
function getTitles(bookProperty: any): string[] {
const allBooks = getAllBooks();
if(typeof bookProperty == 'string') {
return allBooks.reduce((found,book) => {
if(book.author === bookProperty) {
found.push(book.title);
}
return found;
}, []);
} else if (typeof bookProperty == 'boolean') {
return allBooks.reduce((found,book) => {
if(book.available === bookProperty) {
found.push(book.title);
}
return found;
}, []);
}
}
Break-up an object or array into component variables
interface USPostalAddress {
streetAddress1: string;
streetAddress2?: string; // ? means optional
city: string;
state: string;
zip: string;
country: string;
}
const addressData1 = {
streetAddress1: '1001 Main Street',
streetAddress2: '3rd Floor',
city: 'Anytown',
state: 'NY',
zip: '10001-1234',
country: 'USA'
};
// the default value in streetAddress2: stret2 = "" only applies if it is undefined
const {streetAdress1: street1, streetAddress2: street2 = "", city, state, zip, country} = addressData1;
const names = ['Alice', 'Bob', 'Charlie','Dana','Elvis','Fran','George'];
const firstTraditional = names[0];
// the first element in the array will be assigned to firstDestructure, the second to secondDestructure
const [firstDestructure, secondDestructure] = names;
// if names was empty, all the variables would get undefined
// you can set default values
const [firstDestructure = 'Steve', secondDestructure] = names || [];
// we can also get the rest of the elements not assigned in another variable
const [firstDestructure = 'Steve', secondDestructure, ...more] = names || [];
// thanks to this ... notation, it will give us an empty array if we call it with no parameters
// in this example we have a list of strings and we get an array of strings
multiGreet('Alice','Bob', 'Charlie');
function multiGreet(...items) {
items.forEach(
(item) => {
console.log('Hello, '+item)
};
);
}
// if we have an array and we want to pass it as a list of arguments we can do it like this:
multiGreet(...names);
const names = ['Alice','Bob','Charlie','Dana'];
const names2 = ['Isaac','Jane'];
// merge arrays and add another element, which makes sense with what we've said before about getting a list of elements from an array
const names3 = [...names,...names2, Kyle];
const myCar = 'BMW M3';
const useBackTick = `Hello World!`;
const substitutions = `I love ${myCar}!`;
console.log(`Hello, ${item}.`);
function multiGreet(...items: string[]) {
items.forEach(item => {
console.log(friend`Hello, ${item}.`);
});
}
function friend(strings: string[], ...substitutions: string[]) {
if (!substitutions[0]) {
substitutions[0] = 'Friend';
}
return processTaggedTemplate(strings, substitutions);
}
function processTaggedTemplate(strings: string[], substitutions: string[]) {
const result = [];
substitutions.forEach((sub,index) => {
result.push(strings[index],sub);
});
result.push(strings[strings.length -1]);
return result.join('');
}
const names = ['Alice','Bob','Charlie','Dana','Elvis','Fran','George','Hope'];
names.forEach(item => {console.log(item);}); // values
for(let item in names){ // indexes
console.log(names[item]);
}
for (let item of names) { // values
console.log(item);
}
Exporting and importing objects:
- Require.js (AMD format)
- SystemJS (AMD,CommonJS,ES2015,its own)
- node.js (CommonJS)
WHATWG: Web Hypertext Application Technology Working Group
https://whatwg.github.io/loader/
Typescript can Transpile to:
- CommonJS
- AMD
- UMD
- System
With the introduction of ES6 Modules we don't polute the global scope and therefore we have to explicitly export and import the functionality we want to use.
// library.js
function doSomething() {
}
export dosomething;
// program.js
import {doSomething} from "library";
doSomething();
export function helloWorld() {
console.log('Hello World');
}
function helloWorld() {
console.log('Hello World');
}
export {helloWorld}
export {helloWorld, someFunction, someVariable, someClass};
export {wowify as superWowify}
import * as hello from './helloWorld';
hello.hello();
import {hello} from './helloWorld';
hello();
import {hello as h} from './helloWorld';
h();
import {hello, goodbye} from './helloWorld';
hello();
goodbye();
export {wowify as default, mehify};
import {default as wowify} from './wowify';
import wowify, {mehify} from './wowify';
// movie.ts
export default class {
title: string;
director: string;
}
// kids.ts
import AnimatedMovie from './movies';
let cartoon = new AnimatedMovie();
AMD: Asynchronous Module Definition
// tsconfg.json
{
"version": "1.5.0-beta",
"compilerOptions": {
"target": "es5",
"module": "amd",
// ...
}
}
<script data-main="program" src="/scripts/require/require.js"></script>
...
// tsconfg.json
{
"version": "1.5.0-beta",
"compilerOptions": {
"target": "es5",
"module": "commonjs",
// ...
}
}
// tsconfg.json
{
"version": "1.5.0-beta",
"compilerOptions": {
"target": "es5",
"module": "umd",
// ...
}
}
- System.register()
- Polyfill for new System object
- AMD
- CommonJS
- Shim for "Global" JS
- Non-JS, CSS, JSON images
// tsconfg.json
{
"version": "1.5.0-beta",
"compilerOptions": {
"target": "es5",
"module": "system",
// ...
}
}
<script src="/scripts/systemjs/sytem.js"></script>
<script src="../system-config.js"></script>
- constructor functions
- instance properties and methods
- static properties and methods
- inheritance
- Before ES6
- Prototypal Inheritance or Delegation
- Simple Object Literals
- Factory Functions
- Classes
class Contact {
}
const alice = new Contact();
alice.name = 'Alice';
alice.phone = '555-1212';
alice.email = '[email protected]';
console.log(JSON.stringify(alice));
class Contact {
name: string;
phone: string;
email: string;
}
const alice = new Contact();
alice.name = 'Alice';
alice.phone = '555-1212';
alice.email = '[email protected]';
console.log(JSON.stringify(alice));
class Contact {
name: string;
phone: string;
email: string;
constructor(name, phone, email?) {
// the question mark it's from typescript and makes it optional
this.name = name:
this.phone = phone;
this.email = email;
}
const alice = new Contact('Alice','555-1212','[email protected]');
}
const alice2 = new Contact({name: 'Alice', phone: '555-1212'});
- public (by default)
- protected
- private (but not at runtime)
class Contact {
email: string;
phone: string;
name: string;
greet(greetee: string) {
return `Hello, ${greetee}, my name is ${this.name}`;
}
constructor({name, phone, email = undefined}) {
this.name = name;
this.phone = phone;
this.email = email;
}
}
Class declerations are not hoisted
class Employee extends Contact {
employeeId: string;
hireDate: Date;
}
const pat = new Employee({name: 'Pat', phone: '555-1213'});
pat.hireDate = new Date('2015-01-01');
console.log(pat.hireDate.toUTCString());
console.log(pat.greet('Renee'));
console.log(pat instanceof Employee); // true
console.log(pat instanceof Contact); // true
Try to avoid deep class hierarchies
Compose complex classes by implementing multiple interfaces
class Employee extends Contact {
employeeID: string;
hireDate: Date;
constructor({name, phone, email = undefined, employeeID, hireDate}) {
// using super
super({name, phone, email});
this.employeeI = employeeID;
this.hireDate = hireDate;
}
greet(greetee: string) {
// using super
return super.greet(greetee) + ' By the way, I'm an employee!;
}
}
class Employee extends Contact {
private _employeeID: string;
get employeeId() {
return this._employeeID;
}
set employeeID(value) {
// if we set a value in the constructor, it will call this setter
this._employeeID = (value || "").toLocaleUpperCase();
}
}
const useFakes = true;
if (!useFakes){
var MyWebService = class MyWebService {
getData(id) {
// expensive call.
}
}
} else {
var MyWebService = class Fake_MyWebService {
getData(id) {
console.log(`Just logging: ${id}`);
}
}
}
var webService = new MyWebService();
webService.getData(5);
const useFakes = true;
if (!useFakes){
var MyWebService = new (class MyWebService {
getData(id) {
// expensive call.
}
})();
} else {
var MyWebService = new (class Fake_MyWebService {
getData(id) {
console.log(`Just logging: ${id}`);
}
})();
}
var webService = MyWebService;
webService.getData(5);
- Utility functions
- Caching
- Tracking class metadata
class TestStatic {
static doubleNumber(num) {
return num * 2;
}
static count = 0; // only works with Typescript not ES6
constructor() {
TestStatic.count += 1;
}
}
console.log(TestStatic.doubleNumber(10));
var ts1 = new TestStatic();
var ts2 = new TestStatic();
console.log(TestStatic.count);
class Library {
constructor(public name: string) {}
static description: string = 'A source of knowledge.';
}
let lib = new Library('New York Public Library');
let name = lib.name; // available on instances of the class
let desc = Library.description; // available on the class
It lets us define our own types.
An interface in typescript is like a contract that defines a type:
- contracts define types
- compiler enforces that contract via type checking
- collection of property and method definitions
- uses duck typing
- once the type is defined, we cannot add properties that aren't defined in the interface
Duck Typing: "When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck."
interface Duck {
walk:() => void;
swim: () => void;
quack: () => void;
}
let probablyDuck = {
walk: () => console.log('walking like a duck'),
swim: () => console.log('swimming like a duck'),
quack: () => console.log('quacking like a duck')
};
function flyOverWater(bird: Duck) {}
flyOverWater(probablyDuck); // works!!
- "interface" keyword
- list properties with their types
- optional properties denoted with "?"
- provide function signatures - no implementation
Interfaces don't have an implementation in ES5. A tanspile file of an interface is an empty file.
interface Book {
id: number;
title: string;
author: string;
pages?: number;
markDamaged: (reason: string) => void;
}
interface ISprite {
x: number;
y: number;
imageUrl: string;
update: () => void;
}
import { Category } from './enums';
interface Book {
id: number;
title: string;
author: string;
available: boolean;
category: Category;
pages?: number;
markDamaged?: (reason: string) => void;
}
export { Book };
interface StringGenerator {
(chars: string, nums: number): string;
}
// vs, in the later we use => instead of :
let idGenerator: (chars:string, nums: number) => string;
interface LibraryResource {
catalogNumber: number;
}
interface Book {
title: string;
}
interface Encyclopedia extends LibraryResource, Book {
volume: number;
}
//
let reBook: Encyclopeida = {
catalogNumber: 1234,
title: 'The Book of Everything',
volume: 1
};
Template for creating objects. Provided state storage and behavior. Encapsulate reusable functionality.
Perform initialization of a class.
class ReferenceItem {
constructor(title: string, publisher?: string) {
// perform initialization here
}
let encyclopedia = new ReferenceItem('WorldPedia','WorldPub');
}
class ReferenceItem {
numberOfPages: number;
// having get and set editor means we have a property editor.
// setters do not have a return value
get editor(): string {
// custom getter logic here, should return a value
}
set editor(newEditor: string) {
// custom setter logir goes here
}
printChapterTitle(chapterNum: number): void {
// print title here
}
}
class Author {
name: string;
constructor(authorName: string) {
name = authorName;
}
}
// vs
class Author {
constructor(public name: string) {}
}
- public (by default, and not required)
- private
- protected
class ReferenceItem {
title: string;
year: number;
constructor(newTitle: string, newYear:number) {
console.log('Creating a new ReferenceItem...');
this.title = newTitle;
this.year = newYear;
}
printItem(): void {
// Template strings
// this keyword to reference properties and methods in the same class
console.log(`${this.title} was in ${this.year}.`);
}
}
class ReferenceItem {
private _publisher: string;
static department: string = 'Research';
constructor(public newTitle: string, private newYear:number) {
console.log('Creating a new ReferenceItem...');
}
printItem(): void {
// Template strings
// this keyword to reference properties and methods in the same class
console.log(`${this.title} was in ${this.year}.`);
console.log(ReferenceItem.department);
}
get publisher(): string {
return this._publisher.toUpperCase();
}
set publisher(newPublisher: string) {
this._publisher = newPublisher;
}
}
// vs ES5
var ReferenceItem = (function () {
function ReferenceItem(newTitle, newYear) {
this.newTitle = newTitle;
this.newYear = newYear;
console.log('Creating a new ReferenceItem...');
}
ReferenceItem.prototype.printItem = function () {
// Template strings
// this keyword to reference properties and methods in the same class
console.log(this.title + " was in " + this.year + ".");
console.log(ReferenceItem.department);
};
Object.defineProperty(ReferenceItem.prototype, "publisher", {
get: function () {
return this._publisher.toUpperCase();
},
set: function (newPublisher) {
this._publisher = newPublisher;
},
enumerable: true,
configurable: true
});
ReferenceItem.department = 'Research';
return ReferenceItem;
}());
exports.ReferenceItem = ReferenceItem;
interface Librarian {
doWork: () => void;
}
class ElementarySchoolLibrarian implements Librarian {
doWork() {
console.log('Reading to and teaching children...');
}
}
let kidsLibrarian: Librarian = new ElementarySchoolLibrarian();
kidsLibrarian.doWork();
import { Librarian } from './interfaces';
class UniversityLibrarian implements Librarian {
name: string;
email: string;
department: string;
// in the following snippet we'll see that this method is a methond in the prototype
assistCustomer(custName: string) {
console.log(this.name + ' is assisting ' + custName);
}
}
export { UniversityLibrarian };
// vs ES5 version
"use strict";
var UniversityLibrarian = (function () {
function UniversityLibrarian() {
}
UniversityLibrarian.prototype.assistCustomer = function (custName) {
console.log(this.name + ' is assisting ' + custName);
};
return UniversityLibrarian;
}());
exports.UniversityLibrarian = UniversityLibrarian;
- Base classes that may not be instantiated
- May contain implementation details
- Abstract methos are not implemented
abstract class Sprite implements ISprite {
x: number;
y: number;
imageUrl: string;
abstract update();
}
class Player extends Sprite {
update() {
// do whatever
}
}
class Monster extends Sprite {
update() {
// do whatever
}
}
abstract class ReferenceItem {
protected _publisher: string;
static department: string = 'Research';
constructor(public newTitle: string, private newYear:number) {
console.log('Creating a new ReferenceItem...');
}
printItem(): void {
// Template strings
// this keyword to reference properties and methods in the same class
console.log(`${this.title} was in ${this.year}.`);
console.log(ReferenceItem.department);
}
get publisher(): string {
return this._publisher.toUpperCase();
}
set publisher(newPublisher: string) {
this._publisher = newPublisher;
}
abstract printCitation(): void;
}
class Encyclopedia extends ReferenceItem {
constructor(newTitle: string, newYear: number, public edition: number) {
super(newTitle, newYear);
}
printItem(): void {
super.printItem();
console.log(`Edition: ${this.edition}`);
}
printCitation(): void {
console.log(`${this.title} - ${this.year}`);
}
}
let Newspaper = class extends ReferenceItem {
printCitation(): void {
console.log(`Newspaper: ${this.title}`);
}
}
Code that work with multiple types.
They accept "type parameters" for each instance of invocation and they apply to functions, interfaces and classes.
They specify the type a generic will operate over. They are coded separate from function parameters inside angle brackets. And they are conventionally represented by the letter 'T' Array<T>
.
let poetryBooks: Book[];
let fictionBooks: Array<Book>;
let historyBooks = new Array<Book>(5);
function logAndReturn<T>(thing: T): T {
console.log(thing);
return thing;
}
let someString: string = logAndReturn<string>('log this');
let newMag: Magazine = { title: 'Web Dev Monthly' };
let someMag: Magazine = logAndReturn<Magazine>(newMag);
interface Inventory<T> {
getNewesItem: () => T;
addItem: (newItem: T) => void;
getAllItems: () => Array<T>;
}
let bookInventory: Inventory<Book>;
// populate the inventory here...
let allBooks: Array<book> = bookInventory.getAllItems();
We have to bear in mind that we can only use properties and methods that are generic to any type.
class Catalog<T> implements Inventory<T> {
private catalogItems = new Array<T>();
addItem(newItem: T) {
this.catalogItems.push(newItem);
}
// implement other interface methods here
}
let bookCatalog = new Catalog<Book>();
- Describe types that may be passed as a generic parameter.
- extends keyword applies constraint
interface CatalogItem {
catalogNumber: number;
}
class Catalog<T extends CatalogItem> implements Inventory<T> {
// implement interface methods here
}
interface ShelfItem {
title: string;
}
export default class Shelf<T extends ShelfItem> {
private _items: Array<T> = new Array<T>();
add(item: T): void {
this._items.push(item);
}
getFirst(): T{
return this._items[0];
}
find(title: string): T{
return this._items.filter(item => item.title === title)[0];
}
printTitles(): void {
this._items.forEach(item => console.log(item.title));
}
}
Typescript Github Page
Typescript Wiki
Compiler Options
tsc --help
- module format output
tsc --module
ortsc ---m
- module resolution
tsc --moduleResolution
- Classic
- Node
- target
tsc --target
ortsc --t
- watch
tsc --watch
ortsc --w
tsc --outDir
tsc --noImplicitAny
# app.ts is the entry point (and than follows the references)
tsc --t ES5 --outdir js --m commonjs --sourceMap app.ts
- Marks the root of a Typescript project
- Specifies Typescript compiler object
- Specifies files to include in the project
// it also goes recursiveley for the dependencies
{
"compilerOptions": {
"target": "es5",
"outDir": "js",
"module": "commonjs",
"sourceMap": false
},
"files": [
"app.ts",
"classes.ts"
],
"exclude": [
"node_modules",
"lib"
]
}
If we want to use the config file but inside another project directory we can do the following:
tsc --project ./lib
They are files with type information for a library. They contain no implementation details and are basically interfaces. Primarily used as a Typescript wrapper for javascript libraries. The main benefit is design-time tool for type-checking and editor support.
File names end with .d.ts
.
Some npm packages already give them, but it is quite a new feature.
Definitely Typed Github Repository
Definitely Typed Is the most used/knwon repository, it is a huge repository.
- Direct download from the repository
- Nuget (for visual studio)
- tsd (type definition manager)
- typings (type definition manager for multiple sources)
npm init -f
npm install lodash --save
- We copy the lodash.d.ts info from the Github Repository.
- We add the
//<ref
to the app.ts/// <reference path="lodash.d.ts" />
/// <reference path="lodash.d.ts" />
// this can only work on a client not in node, because is trying to use more than one module per file
import * as _ from 'lodash';
let snakeCaseTitle = _.snakeCase('For Whom the Bell Tolls');
console.log(snakeCaseTitle);
- find and download type definitions
- uses DefinitelyTyped exclusively
- manages references to installed definitions
- stores "tripe-slash" references in a single file
- it's deprecated
The same as tsd but it isn't yet widely adopted.
Typings is a type definition manager (multiple sources).
npm install -g typings
typings install lodash --save
They are created with the declare syntax and do not define an implementation.
// cadCatalog.d.ts
declare module "CardCatalog" {
export function printCard(callNumber: string): void;
}
// app.ts
/// <reference path="cardCatalog.d.ts" />
import * as catalog from "CardCatalog";