- Simple JSON text file named
tsconfig.json
- Stores compiler options used with the project
- Specifies files to be included or excluded in compilation
- Supports configuration inheritance
- Static Types: variables, parameters, return types,etc.
- Organization: Making it easier to manager a large codebase.
- classes
- namespaces
- modules
- interfaces
- Tooling:
- static type analysis
- many "instant" errors
- detect unused data / unreachable code
- source maps - debug directly in TypeScript
- boolean
- number
- string
- array
- enum
- void
- null
- undefined
- never
- any
let someValue: number | string;
someValue = 42;
someValue = 'Hello Or Hasson';
let basicString: string;
basicString = null;
(ERROR)
basicString = undefined;
(ERROR)
let nullableString: string | null;
nullableString = null;
(OK)
nullableString = undefined;
(ERROR)
let mysteryString: sring | null | undefined;
mysteryString = null;
(OK)
mysteryString = undefined;
(OK)
let value: any = 5;
let fixedString: string = (
<number>value).toFixed(4);
console.log(fixedString); // 5.0000
// another syntax for Type Assetion
let fixedString: string = (value as number).toFixed(4);
console.log(fixedString); // 5.0000
// JavaScript
function dullFunc(value1, value2) {
return "I love the way you love the way you love.";
}
// TypeScript
function funFunc(score: number, message?: string): string {
return "I love the way you love the way you love.";
}
function dullFun(value1, value2) {
return "I love the way you love the way you love.";
}
ERROR
TS7006: Parameter
'value1'
implicityly
has
an
'any'
type.ERROR
TS7006: Parameter
'value2'
implicityly
has
an
'any'
type.
function sendGreeting(greeting: stirng = 'Good morning!'): void {
console.log(greeting);
}
sendingGreeting(); // Good morning!
sendGreeting('Good afternoon, Or Hasson!'); // Good afternoon, Or Hasson!
- Interfaces:
- Define a new type
- Properties(signatures)
- Methods (signatures)
- Cannot be instantiated
- Classes:
- Define a new type
- Properties (with implementation)
- Methods (with implementation)
- Can be instantiated
// Creating an Interface:
interface Employee {
name: string;
title: string;
}
interface Manger extends Employee {
department: string;
numOfEmployees: number;
scheduleMeeting: (topic: string) => void;
}
- Method implementation
- Property implementation
- Accessors (getters and setters)
- Access modifiers
- public
- private
- protected
class Developer {
department: string;
private _title: string;
get title(): string {
return this._title;
}
set title(newTitle: string) {
this._title = newTitle.toUpperCase();
}
documentRequirements(requirements: string): void {
console.log(requirements);
}
}
class WebDeveloper extends Developer {
favoriteEditor: string;
writeTypeScript(): void {
// write awesome code
}
}
let webdev: WebDeveloper = new WebDeveloper();
webdev.department = 'Software Engineering';
webdev.favoriteEditor = 'WebStorm';
interface Employee {
name: string;
title: string;
logID: () => string;
}
class Engineer implements Employee {
name: string;
title: string;
logID() {
return `${this.name}_${this.title}`;
}
}
class WebDeveloper extends Developer {
static jobDescription: string = 'Build cool things!';
static logFavoriteProtocol() {
console.log('HTTPS, of course!');
}
logJobDescription(): void {
console.log(WebDeveloper.jobDescription);
}
}
WebDeveloper.logFavoriteProtocol();
class Developer {
constructor() {
console.log('Creating a new developer.');
}
}
class WebDeveloper extends Developer {
readonly favoriteEditor: string;
constructor(editor: string) {
super();
this.favoriteEditor = editor;
}
}
- Encapsulation
- Re-usability
- Create higher-level abstractions
// person.ts
export interface Person {
}
export function hireDeveloper(): void {
}
export default class Employee {
}
class Manager {
} // not accessible outside the module
interface Person {
}
function hireDeveloper(): void {
}
class Employee {
}
class Manager {
}
export {Person, hireDeveloper, Employee as StaffMember};
// player.ts
import {Person, hireDeveloper} from './person';
let human: Person;
import Worker from './person';
let engineer: Worker = new Worker();
import {StaffMember as CoWorker} from './person';
let emp: CoWorker = new CoWorker();
import * as HR from './person';
HR.hireDeveloper();
// relative imports
import {Laptop} from '/hardware';
import {Developer} from './person';
import {NewHire} from '../HR/recruiting';
// non-relative imports
import * as $ from 'jquery';
import * as lodash from 'lodash';
tsc --moduleResulution Classic | Node
- Classic:
- Default when emitting AMD, UMD, System, or ES2015 modules
- Simple
- Less Configurable
- Node:
- Default when emitting CommonJS modules
- Closely mirrors Node module resolution
- More configurable
// File: /Source/MultiMath/player.ts
import {Developer} from './person';
/**
* The import will search:
* 1. /Source/MultiMath/person.ts
* 2. /Source/MultiMath/person.d.ts
*/
// File: /Source/MultiMath/player.ts
import {Developer} from 'person';
/**
* The import will search:
* 1. /Source/MultiMath/person.ts
* 2. /Source/MultiMath/person.d.ts
* 3. /Source/person.ts
* 4. /Source/person.d.ts
* (continue searching up the directory tree)
*/
// File: /Source/MultiMath/player.ts
import {Developer} from 'person';
/**
* The import will search:
* 1. /Source/MultiMath/person.ts
* 2. /Source/MultiMath/person.tsx
* 3. /Source/MultiMath/person.d.ts
* 4. /Source/MultiMath/person/package.json (with "types" property)
* 5. /Source/MultiMath/person/index.tsx
* 6. /Source/MultiMath/person/index.d.ts
*
*/
// File: /Source/MultiMath/player.ts
import {Developer} from 'person';
/**
* The import will search:
* 1. /Source/MultiMath/node_modules/person.ts (person.tsx, person.d.ts)
* 2. /Source/MultiMath/node_modules/person/package.json (with "types" property)
* 3. /Source/MultiMath/node_modules/@types/person.d.ts
* 4. /Source/MultiMath/node_modules/person/index.ts (index.tsx, index.d.ts)
* 5. /Source/node_modules/person.ts (person.tsx, person.d.ts)
* 6. /Source/node_modules/@types/person.d.ts
* 7. /Source/node_modules/person/index.ts (index.tsx, index.d.ts)
*/
- TypeScript wrapper for JavaScript libraries
- Types for variables, functions, etc.
- Define valid property names.
- Define function parameters.
- Development-time tool
- Filenames end with .d.ts
- Available for thousands of libraries
- GitHub repository containing thousands of type declaration files.
- Declaration files often maintained independent of related JavaScript library.
- Source for installation utilities.
- Installed with npm
- Packages installed from
@types/<name>
- Sourced from the DefinitelyTyped repository.
- Store state
- Pass state
- Group related functionality
- Model real-world objects
- Constructor Function
- Object Literal
- Object.create()
- Class
Programs are composed of objects which communicate with each other, which may be arranged into hierarchies, and which can be combined to form additional objects.
- Code reuse
- Faster development time frames
- Real-world mapping of objects
- Modular architecture
- More maintainable code base
- Abstraction
- Encapsulation
- Inheritance
- Polymorphism
Abstract complex functionality into an object that can be used as the base for other objects.
Objects provide public access points that can be used to interact with private members.
Objects can share functionality from existing objects and create a family hierarchy.
Objects exhibit the same behavior but in a different way.
- Fields
- Properties
- Constructor
- Functions/Methods
class Person {
firstName: string;
lastName: string;
}
Creating a Property: Properties can be defined directly withing a class.
class Person {
private _age: number;
get age() {
return this._age;
}
set age(value: number) {
if (value > 0) {
this._age = value;
}
}
}
class Person {
placeOrder(productId: number, quantity: number): OrderResponse {
return {
status: true,
orderId: 42
};
}
}
Defining a Return Type: TypeScript automatically infers the return type of function/method, however, we can explicitly define one.
class Person {
firstName: string;
lastName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
}
Creating a Class Constructor: A constructor is called when a class is instantiated to create an object. A constructor can accept parameters that can be mapped to properties.
class Person {
constructor(public firstName: string, public lastName: string) {
}
}
Automatic Properties:Properties can be defined in a constructor using accessibility modifiers (public/private) By using automatic property functionality, a property will be generated, and the constructor value will be mapped to it.
Abstraction: Abstract complex functionality into an object that can be used as the base for other objects.
class BankAccount {
constructor(id: number) {
// code...
}
}
class CheckingAccount extends BankAccount {
constructor(id: number) {
super(id); // required
}
}
Inheriting from a Class: Classes can inherit/derive functionality from other classes Use the extends keyword.
Abstract complex functionality into an object that can be used as the base for other objects.
An abstract class can be used as foundation for other classes. Can define concrete members as well as abstract members.
import {AccountType} from "./enums";
abstract class BankAccount {
// Abstract member (must be implented by child)
abstract accountType: AccountType;
// Concrete member
deposit() { /* code ...*/
}
}
- Inheritance provides a way to promote reuse across objects in an application.
- Use the extends keyword for inheritance.
- Call super() in a child class constructor when the base/parent class has a constructor.
- Abstract classes "abstract" functionality serve as the foundation for other classes.
- Create abstract classes and members by using the abstract keyword.
- Interfaces act as a contract that defines a set of rules.
- Interfaces can be used to enforce consistency across different classes in an application.
Creating an Interface
- Interfaces can be used to create custom data types.
- Classes can implement interfaces which can help ensure consistency across an application.
- Interfaces are only used during development (no impact on script/bundle size).
interface DepositWithdrawal {
deposit(amount: number): void;
withdrawal(amount: number): void;
}
interface AccountInfo {
routingNumber: number;
bankNumber: number;
}
Classes can implement interfaces using the TypeScript implements keyword
class ATM implements DepositWithdrawal {
deposit(amount: number) {/*code...*/
}
withdrawal(amount: number) {/*code...*/
}
}
interface DepositWithdrawal {
deposit(amount: number): void;
withdrawal(amount: number): void;
}
Objects exhibit the same behavior but in a different way.
Interfaces can be used as types to define the "shape" of data held in property or that is passed to a function/method or constructor
accounInfo: AccountInfo;
interface AccountInfo {
routingNumber: number;
bankNumber: number;
}
- Interfaces are code contracts.
- Key benefits of using interfaces include:
- Drive consistency across multiple objects.
- Define the "shape" of data passed to a constructor or function/method.
- Use as custom data type.
- Classes can implement an interface by using the implements' keyword.
- Abstract classes and interfaces can both be used to achieve polymorphic behavior.
- Reusable code that works with multiple types.
- May be functions, interfaces, or classes.
- Code that accepts type parameters for each instance or invocation.
- Generics are not just for classes.
- Type-safe versatility.
- Generic constraints increase practicality.
- Generic function types add flexibility.
Stack.ts:
interface DataStructure<T> {
push(newItem: T): void;
pop(): T;
}
export class Stack<T> implements DataStructure<T> {
items: Array<T> = [];
pop(): T {
return this.items.pop();
}
push(newItem: T): void {
this.items.push(newItem);
}
peek(): T {
return this.items[this.items.length - 1];
}
}
main.ts:
import {Stack} from "./stack";
let myNumberStack: Stack<number> = new Stack<number>();
myNumberStack.push(1);
myNumberStack.push(2);
myNumberStack.push(3);
console.log(myNumberStack.pop()); // 3
console.log(myNumberStack.peek()); // 2
console.log(myNumberStack.pop()); // 2
console.log(myNumberStack.pop()); // 1
*** GENERIC CLASSES ARE ONLY GENERIC OVER THEIR INSTANCES. ***
- Use generic interfaces with object literals or generic classes.
- Generic classes offer type-safe versatility (with or without implementing an interface).
- Type constraints increase practicality.
- var
- Globally available in the function in which it is declared.
- "Hoisted" to the top of the function.
- Variable name may be declared a second time in the same function.
- let and const
- Only available in the block in which it is declared.
- Not "hoisted" to the top of the block.
- Variable name may only be declared once per block.
Example - var Versus let:
function ScopeTest() {
if (true) {
var old_technique = 'use anywhere';
let new_technique = 'use in this block';
// do some more stuff
}
console.log(old_technique); // works!
console.log(new_technique); // error!
}
- boolean
- number
- array
- enum
- any
- void
enum Category {Mathematics, Biology, Fiction}; // 0,1,2
enum Category {Mathematics = 1, Biology, Fiction}; // 1,2,3
let favoriteCategory: Category = Category.Biology;
console.log(favoriteCategory); // 2
let categoryString = Category[favoriteCategory]; // Biology
Arrays:
- can be declared two different ways
- Accessed and used much like JavaScript arrays.
let strArr1: string[] = ['here', 'I', 'am'];
let strArr2: Array<string> = ['here', 'I', 'am', 'again'];
let anyArr: any[] = [32, true, 'Apple'];
Tuples:
- Array where types for first few elements are specified.
- Types do not have to be the same.
- Additional elements can be any type from those previously specified.
let myTuple: [number, string] = [21, 'bus'];
let firstElement = myTuple[0]; // 21
let secondElement = myTuple[1]; // bus
// other elements can be numbers or strings
myTuple[2] = 101;
myTuple[2] = "Or Hasson";
TypeScript:
- Type
- Arrow functions
- Function types
- Required and optional parameters
- Default parameters
- Rest parameters
- Overloaded functions
JavaScript:
- Limited types and no type checking
- Arrow function (ES2015)
- No function types
- All parameters are optional
- Default parameters (ES2015)
- Rest parameters (ES2015)
- No overloaded functions
- Concise syntax for anonymous functions
- "this" is captured at function creation - not invocation
- Combination of parameter types and return type Variables may be declared with function types
- Variables may be declared with function types
- Function assigned must have the same signature as the variable type
function PublicationMessage(year: number): string {
return 'Date published: ' + year;
}
let publishFun: (someYear: number) => string;
publishFunc = PublicationMessage;
let message: string = publishFun(2021);
- Optional parameters denoted with "?" after parameter name
- Must appear after all required parameters
- Default parameters may be set to a literal value or an expression
function CreateCustomer(name: string, age?: number) {
}
function GetBookByTitle(title: string = 'The JavaScript Programming Language') {
}
function GetBookByTitle(title: string = GetMostPupolarBook()) {
}
- Collects a group of parameters into a single array.
- Denoted with an ellipsis prefix on last parameter.
function GetBooksReadForCust(name: string, ...bookIDs: number[]) {
}
let books = GetBooksReadForCust('Or', 2, 4);
let books2 = GetBooksReadForCust('Hasson', 1, 2, 3, 4, 5, 6);
- Contracts that define types
- Compiler enforces the contract via type checking
- Collection of property and method definitions
- Duck typing
Duck Typing:
interface Duck {
walk: () => void;
swim: () => void;
quack: () => void;
}
let probablyADuck = {
walk: () => console.log('walking like a duck'),
swim: () => console.log('swimming like a fuck'),
quack: () => console.log('quacking like a duck')
}
function FlyOverWater(bird: Duck) {
}
FlyOverWater(probablyADuck); // works!!!
Defining an Interface
interface
keyword
List properties with their types
Optional properties denoted with "?"
Provide function signature - no implementation
interface Book {
id: number;
title: string;
author: string;
pages?: number;
markDamaed: (reason: string) => void;
}
function CreateCustomerID(name: string, id: number): string {
return name + id;
}
interface StringGenerator {
(chars: string, nums: number): string;
}
let IdGenerator = StringGenerator
IdGenerator = CreateCustomerID;
interface LibraryResource {
catalogNumber: number;
}
interface Book {
title: string;
}
interface Encyclopedia extends LibraryResource, Book {
volume: number;
}
let refBook: Encyclopedia = {
catalogNumber: 1234,
title: 'The Book of life',
volume: 120
}
interface Librarian {
doWork: () => void;
}
class ElementarySchoolLibrarian implements Librarian {
doWork() {
console.log('Reading to and teaching children...');
}
}
let kidsLibrarian: Librarian = new ElementarySchoolLibrarian();
kidsLibrarian.doWork();
- Template for creating objects
- Provides state storage and behavior
- Encapsulates reusable functionality
- Define Types
- Properties and Methods
- Constructors
- Access Modifiers
- Inheritance
- Abstract Classes
Method named constructor
- maximum of one per class
Use optional parameters to call different ways
Executed by using the "new" keyword
class ReferenceItem {
constructor(title: string, pblisher?: string) {
// perform initialization here
}
}
let encyclopedia = new ReferenceItem('WorldPedia', 'WorldPub');
class ReferenceItem {
numberOfPages: number;
get editor(): string {
// custom getter logic goes here, should return a value
}
set editor(newEditor: string) {
// custom setter logic goes here
}
printCapterTitle(chapterNum: number): void {
// print title here
}
}
class Author {
name: string;
constructor(authorName: string) {
name = authorName;
}
}
// Better syntax with shourcut that elminated the explicit property
class Author {
constructor(public name: string) {
}
}
class Library {
constructor(public name: string) {
}
static description: string = 'A source of knowledge and inspiration'
}
let lib = new Library('Tel Aviv Public Library');
let name = lib.name; // available on instances of the 'Library' class
let desc = Library.description; // avaiable on the 'Library' class
- public
- private
#
(alternative - it's provide some extra protection (since ES 2021 and later))
- protected
class ReferenceItem {
title: string;
printItem(): void {/** print something here**/
}
}
class Journal extends ReferenceItem {
constructor() {
super();
}
contributors: string[];
}
- Created with the
abstract
keyword - Base classes that may not be instantiated
- May contain implementation details
- Abstract methods are not implemented
- They are modular
- Maintainable
- Reusable
- Native to Node and ES2015
- Organized simply in files and folders.
(periodicals.ts)
/** Option 1 **/
export interface Periodical {
issueNumber: number;
}
export class Magazine implements Periodical {
issueNumber: number;
}
export function GetMagazineByIssueNumber(issue: number): Magazine {
// retrieve and return a magazine
}
(periodicals.ts)
/** Option 2 **/
interface Periodical {
issueNumber: number;
}
class Magazine implements Periodical {
issueNumber: number;
}
function GetMagazineByIssueNumber(issue: number): Magazine {
// retrieve and return a magazine
}
export {Periodical, Magazine, GetMagazineByIssueNumber as GetMag}
news.ts
import {Magazine, GetMag as GetMagazine} from './periodicals';
let newsMag: Magazine = GetMagazine('Weekly News');
tech12.ts
import * as mag from './perdiocals';
let techMag: mag.Magazine = mag.GetMag('React Native Stuff!');
movies.ts
export default class {
title: string;
director: string;
}
kids.ts
import AnimatedMovie from './movie';
let cartoon = new AnimatedMovie();
- Code that works with multiple types
- Accept "type parameters" for each instance of invocation
- Specify the type a generic will operate over
- Listed separate from function parameters inside angle brackets
- _*Conventionally represented by the letter 'T' (e.g.
Array<T>
) - Actual type provided at instance creation or function invocation
Type parameter specifies the type the array can contain
Type parameters are part of the type
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: 'Software Developer Monthly'}
let someMag: Magazine = LogAndReturn<Magazine>(newMag);
interface Inventory<T> {
getNewestItem: () => T;
addItem: (newItem: T) => void;
getAllItems: () => Array<T>;
}
let bookInventory: Inventory<Book>;
// populate the inventory here...
let allBooks: Array<Book> = bookInventory.getAllItems;
class Catalog<T> implements Inventory<T> {
private catalogItems = new Array<T>();
addItem(newItem: T) {
this.catalogItems.push(newItem);
}
// implement other inteface mehtods here...
}
let bookCatalog = new Catalog<Book>();
Describe types that may be passed as a generic parameter
extends
keyword applies constraint
Only types satisfying the constraints may be used
interface CatalogItem {
catalogNumber: number;
}
class Catalog<T extends CatalogItem> implements Inventory<T> {
// implement interface methods here
}
--module / --m
(Tell the compiler which module format it should output such es2015 / CommonJS...);--moduleResolution
(Lets you specify how the TS compiler will attempt to resolve modules Node/Classic);--target / --t
(Lets you specify which version of JS should be output by the compiler);--watch / --w
(Lets you leave the compiler running in watch mode);--outDir
(Lets you specify a directory that should receive all the compiled output files.)--noImplicitAny
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"outDir": "js",
"module": "CommonJS",
"sourceMap": true
}
}
- Marks the root of TypeScript project
- Specifies TypeScript compiler options
Compiling app.ts
file and all his dependencies with "files"
parameter.
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"outDir": "js",
"module": "CommonJS",
"sourceMap": true
},
"files": [
"app.ts"
]
}
Compiling all ts files with ts
extension on current dir and all subs dir with "include"
parameter.
Plus Excluding all files in lib
directory using "exclude"
parameter.
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"outDir": "js",
"module": "CommonJS",
"sourceMap": true
},
"include": [
"**/*.ts"
],
"exclude": [
"./lib/*"
]
}
- Files with type information for library.
- Contain no implementation details.
- Primarily used as a TypeScript wrapper for JavaScript libraries.
- Design-time tool for type-checking and editor support
- File names end with
.d.ts
- Install with npm
@types/<library name>
NOT A REPLACEMENT FOR INSTALLING THE ACTUAL LIBRARY
Each TypeScript Project on a workstation can be of a different version.
There can also be one globally installed version of TypeScript.
- Local Version: Found within a project's directory, only used by that project.
- Global Version: Fallback for when there is not a local version.
- Embedded Version: Fixed version built into some software ide (i.e., VSCode, WebStorm).
Installing TypeScript Globally: npm install -g typescript
Installing TypeScript Locally: npm install --save-dev typescript
- Turns TypeScript into browser-compatible language
- Browsers understand JavaScript, but not TypeScript
- Results may be different based on compiler version
- Can be executed automatically watching code changes
- Using tsconfig.json allows us to customize TypeScript to suit of our project.
- Defines which TypeScript files should be compiled and the resulting structure.
- Which TypeScript features to use when compiling.
- Varies from project to project...
{
"extends": "@tsconfig/node12/tsconfig.json",
// inherited from standard package
"compilerOption": {
"module": "commonjs",
// modifies the format of JavaScript output
"noImplicitAny": true,
//prevents developers from using "any" type
"removeComments": true,
// removes comments from generated code
"sourceMap": true
// created a source map used for debugging
},
"include": [
"src/**/*"
]
// defines which files should be compiled
}
Example TypeScript Configuration:
tsconfig files take the form of a JSON object.
There are hundreds of options available - above are some of the most common.
More about tsconfig
package.json
- Tracks versions of TypeScript and ESLint (used to enforce coding style), contains shortcuts for
building and watching TypeScript code.
index.ts
- Contains code which serves the application, and references to other TypeScript files
tsconfig.json
- Configures how TypeScript should be compiled, and the source and output file locations
Effectively configuring the compiler allows us to design a build process that suits our app, and not the other way
around.
- Output Format: Specify format of generated code(ES3, ES6,ESNext, etc.)
- Supported Features: Restrict certain TypeScript features (e.g.,any type)
- Style Guidelines: Codify and enforce style (line breaks, tab size, etc.) among large teams
- Architecting your application so that builds occur automatically lets your developers focus on completing their tasks.
- Compiler executes automatically when code is edited
- Other tooling (test, etc.) can also be triggered
- Can ignore specific files (e.g, node_modules)
More info about configuring watch
- Collection of compiler options and values
- Available locally or as a package maintained by TypeScript
- Any option can be overwritten
Extending Default Configuration
The two tsconfig.json
files below are equivalent
{
"extends": "@tsconfig/node12/tsconfig.json"
}
{
"$schema": "https://json.schemastore.org/tsconfig",
"display": "Node 12",
"compilerOptions": {
"lib": [
"es2019",
"es2020.promise",
"es2020.bigint",
"es2020.string"
],
"module": "commonjs",
"target": "es2019",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFilesNames": true
}
}
tsconfig.json
Explained:
"lib"
- Specifies which libraries or polyfills should be included in build.
E.g, including es2020.promise
will enable build code to work on older browsers with no build in promise spec.
"module"
- Specifies how to transform code when files refer to each other with require or import.
"target"
- Specifies output code format.
"strict"
- Prevents compilation on any minor type errors or style inconsistencies.
A collection of bases is maintained by the TypeScript project.
- recommended: Enforces strict style and targets ES2015.
- create react app: Settings needs for
jsx
interoperability. - node: Outputs modern server JavaScript
require
,async
,etc.
Multi-file Complication:
- Creates one JavaScript file for every target TypeScript file
- Each file must be loaded for the application to work in a browser
- File must be concatenated or use require to work in Node.js
- Possible to update just one generated file in production
- Standard compilation option for TypeScript
Single-file Compilation:
- Combines all TypeScript files into one single JavaScript file
- Only a single file must be loaded for the application to work in a browser
- Single file will work when invoked as a Node script
- Updated production code must be pushed in its entirety
- Additional tooling (Webpack, Babel) needed
- Compiling a TypeScript application to a single file generally makes it easier to deploy as both a web and server-side application.
- Greater support for isomorphic applications
- Fewer HTTP requests, simpler deployment to web applications
- Greater consistency across browser / Node versions
Project references break large TypeScript applications into smaller blocks that can be built, imported and modified separately.
- Separate application into logical silos.
- Customize build steps for each sub-project.
- Avoid building unnecessary files.
Configuring Project References
tsconfig.json
{
"references": [
{
"path": "../performance"
}
// directory contains tsconfig.json file
]
}
- Projects referenced this way must have composite enabled.
- Projects will be rebuilt as infrequently as possible.
- Build flag will cause compiler to rebuild all projects
- Circular dependencies must be avoided
Type Declaration files let us add typings to values exported from normal JavaScript files.
- Code Hints: Autocompletion and pre-compile warnings
- Type Checking: More sophisticated type checking during compile
- External and Internal: Use community declarations or author for your own project
- With any major JS library or framework, use a declaration file downloaded from a community repository (i.e. Definitely Typed)
- With a locally authored JavaScript tool, create a declaration file and include it with that tool
The open-source community has gathered definitions for hundreds of legacy JavaScript libraries.
- Authoring original d.ts files for npm libraries not usually necessary.
- Works for most libraries found in legacy projects - jQuery, underscore, etc.
- Modern releases of libraries such as jQuery already include declaration files.
- Add time-saving code hints for developers
- Prevent builds which would result in a type error
- Developers can focus on task at hand
- Author your own, or use Definitely Typed
One of TypeScript's main advantages of JS is easier debugging in many cases.
- Type errors stopped at compile time
- Additional tooltips, code hints prevent errors
- Common pitfalls (such as switch statements lacking a break), are disabled
- Incorrectly written function and miscalculations
- Errors arising from corner cases and user input
- Unanticipated values from third party APIs
- Couples generated code with source code
- Browser will show source file, not generated file, while debugging
- Can be embedded entirely within generated file
Enabling Sources Maps
{
"compilerOptions": {
"sourceMap": true
}
}
- Tool for evaluating application source code
- Capable of analyzing code style - bracket spacing, line breaks, tabs and spaces, etc.
- Works with continuous integration - pull requests with incorrectly styled code can be rejected automatically
- Large teams
- Large Projects
- Projects with indefinite scope
- When more unified style is needed
- Styling and spacing TypeScript specific code (e.g, type annotations)
- Disallowed keywords(with,do)
- Preferred code conventions (e.g., requiring classes to always define a constructor)
- Invisible style choices (tabs vs spacing, empty new line at EOF)
- Front-end applications are increasingly complex
- Organization and structure are critical
Importing and Exporting - Easily make code in a module public or private
- Avoid repetition and boilerplate code
- Modules are always evaluated in strict mode
- Strictly opt-in
- Add use strict to every JavaScript file
- Avoid even more repetition
- Modules are never evaluated in the global scope
- The window object is available to all modules
- Only exported code can be imported
- Modules cannot be loaded locally
- Modules are loaded asynchronously and executed on ready
- Members are scoped to the module
- Values can be exported
- Referred to as namespaces
namespace MyNamedInternalModule {
const privateVar = 'private';
export const publicVar = 'public';
}
console.log(MyNamedInternalModule.publicVar); // public
- Typically, modules will export values of functionality
Default exports differ from names exports in several ways, and use a different import syntax
Any declaration can be exported
- Named exports
- Renamed exports
- Export statements
- Barrel files
- Default exports
- Classic (backwards-compatibility)
- Node (default)