Typescript - deependhamecha/angular GitHub Wiki

tsconfig.json

The presence of a tsconfig.json file in a directory indicates that the directory is the root of a TypeScript project.

A typescript project compiles by

  • Searching for tsconfig.json in current directory and progressing towards parent directories. OR
  • Specifying --project with path to tsconfig.json

If the "files" and "include" are both left unspecified, the compiler defaults to including all TypeScript (.ts, .d.ts and .tsx) files in the containing directory and subdirectories except those excluded using the "exclude" property. JS files (.js and .jsx) are also included if allowJs is set to true.

Files in the directory specified using the "outDir" compiler option are always excluded unless explicitly included via the "files" or "include" property.

If you specify files then exclude will be ignored.

If a file B.ts is referenced by another file A.ts, then B.ts cannot be excluded unless the referencing file A.ts is also specified in the "exclude" list.

If the input includes index.ts, then index.d.ts and index.js are excluded.

@types

By default all visible “@types” packages are included in your compilation. Packages in node_modules/@types of any enclosing folder are considered visible; specifically, that means packages within ./node_modules/@types/, ../node_modules/@types/, ../../node_modules/@types/, and so on.

If typeRoots is specified, only packages under typeRoots will be included.

{
   "compilerOptions": {
       "typeRoots" : ["./typings"]
   }
}

This config file will include all packages under ./typings, and no packages from ./node_modules/@types.

If types is specified, only packages listed will be included.

{
   "compilerOptions": {
       "types" : ["node", "lodash", "express"]
   }
}

This tsconfig.json file will only include ./node_modules/@types/node, ./node_modules/@types/lodash and ./node_modules/@types/express. Other packages under node_modules/@types/* will not be included.

Specify "types": [] to disable automatic inclusion of @types packages.

Configuration inheritance with extends

Decorators

Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript.

To enable experimental support for decorators, you must enable the experimentalDecorators compiler option either on the command line or in your tsconfig.json:

tsc --target ES5 --experimentalDecorators
{
  "compilerOptions": {
    "target": "ES5",
    "experimentalDecorators": true
  }
}

Type Inference

Typescript can remember a value's type event if you didn't provide a type annotation, and it will enforce that type moving forward.

let i = 1;
i += 'd'; // Error
let x = {x:1}; // x's type is {x:number}
x.y = 2; // Error

If you do not put type, then it will be of any type.

function square(num) { // num will be here 'any' type
  return num * num;
}
const colors = ['red', 'orange', 'yellow'];
colors.map(color => { // color wont be any type but rather string type, taken from array elements.
  return color.toUpperCase();
});

Default values to functions

function dude(str: string='DEFAULT', n: number) {
    
}

dude(1); // Error

Never

The never type represents values that NEVER occur. We might use it to annotate a function that always throws an exception, or a function that never finishes executing.

Don't confuse with void - void returns undefined or null, which is technically still a type of value. With never, a function doesn't event finish executing.

Intersection Types

type Circle = {
    radius: number;
};

type Colorful = {
    color: string;
}

type ColorfulCircle = Circle & Colorful;

const happyFace: ColorfulCircle = {
    color: '#fff',
    radius: 12
};
type Circle = {
    radius: number;
};

type Colorful = {
    color: string;
}

type ColorfulCircle = Circle & Colorful & {dude: number};

const happyFace: ColorfulCircle = {
    color: '#fff',
    radius: 12,
    {
      dude: 1
    }
};

Union Types

type Dog = {
    bark: boolean
}

type Cat = {
    meow: boolean;
}

type CatDog = Cat | Dog;

var catdog: CatDog = {meow: true};

Literal Types

type DayOfWeek = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday";

let today: DayOfWeek = "Monday";
let today: DayOfWeek = "Someday"; // Wont work

Tuples (Only in typescript)

Arrays of fix length with type strictness on indexes.

let myTuple: [number, string];
myTuple = [1, 'abc'];
myTuple = ['abc', 'abc']; // Error

Enum

enum OrderStatus {
    PENDING, SHIPPED, DELIVERED=23, RETURNED,
}

const myStatus = OrderStatus.DELIVERED;

function isDelivered(status: OrderStatus) {
    return status === OrderStatus.DELIVERED;
}

function isPending(status: OrderStatus) {
    return status === OrderStatus.PENDING;
}

console.log(isDelivered(OrderStatus.DELIVERED)); // true
console.log(isDelivered(23)); // true
console.log(isPending(0)); // true

By default, it has value with respect to index. You can also give it a number, string, boolean value.

Consider, this

enum OrderStatus {
    PENDING, SHIPPED, DELIVERED=23, RETURNED,
}

converts to

var OrderStatus;
(function (OrderStatus) {
    OrderStatus[OrderStatus["PENDING"] = 0] = "PENDING";
    OrderStatus[OrderStatus["SHIPPED"] = 1] = "SHIPPED";
    OrderStatus[OrderStatus["DELIVERED"] = 23] = "DELIVERED";
    OrderStatus[OrderStatus["RETURNED"] = 24] = "RETURNED";
})(OrderStatus || (OrderStatus = {}));

Now, if you put this

const enum OrderStatus {
    PENDING, SHIPPED, DELIVERED=23, RETURNED,
}

const order = {
  orderNumber: 203,
  status: OrderStatus.PENDING
};

then its javascript is,

"use strict";
const order = {
  orderNumber: 203,
  status: 0 /* OrderStatus.PENDING */
};

It does not consider enum if you use it in a constant but remember to put it const enum.

types vs interfaces

interface Point {
    x: number;
    y: number;
}

interface Point {
    a: number;
    b: number;
}

const pt: Point = {x:1, y:2, a: 3, b:4};

It will extend interfaces with same name. You cannot do same with types.

However, with types,

type Name = {name: string};

type Person = Name & {age: number};

const person: Person = {
    name: 'Deepen',
    age: 31
};

Its equivalent in interface is,

interface Name {
    name: string;
}

interface Person extends Name {
    age: number;
}

const person: Person = {
    name: 'Deepen',
    age: 31
};

Configurations

You can create configuration file tsconfig.json with tsc --init

Generics

/**
 * Generics
 */
function identity<Type>(item: Type): Type {
    return item;
}
identity<boolean>(true);



function identity1<T>(item: T): T { // T is just a convention, you can use any Character/Word
    return item;
}
identity1<string>('true');



function getData<T>(list: T[]): T[] {
    return list.map(e => e);
}
getData<string>(['A', 'B', 'C']);
getData(['A', 'B', 'C']); // Type is inferred



function merge<T, U>(object1: T, object2: U) {
    return {
        ...object1,
        ...object2
    };
}

const comboObj = merge<{name: string}, {pets: string[]}>({name: 'Colt'}, {pets: ['blue', 'elton'] });
const comboObj1 = merge({name: 'Colt'}, {pets: ['blue', 'elton'] }); // inferred



/**
 * Here is the problem though, {...true} will return an empty {} so you want T as atleast object type
 */
function merge1<T extends object, U extends object>(object1: T, object2: U) {
        return {
        ...object1,
        ...object2
    };
}

// console.log(merge1({name: 'Colt'}, 9)); // Wont work since its a number type
console.log(merge1({name: 'Colt'}, {name: 9}));



/**
 * This will return an Array of unknown
 */
function makeEmptyArray<T>(): T[] {
    return [];
}
const strings = makeEmptyArray();

/**
 * Now, if here type is not inferred since there are no values returned and instead of unknown you want a default type parameter.
 */
function makeEmptyArray1<T = number>(): T[] {
    return [];
}

const num1 = makeEmptyArray1(); // Which makes it optional
const bool1 = makeEmptyArray1<boolean>();

Type Predicates

/**
 * Type Predicates
 */
interface Cat {
    name: string;
    numLives: number;
}

interface Dog {
    name: string;
    breed: string;
}

const isCat = (animal: Cat | Dog): animal is Cat => {
    return (animal as Cat).numLives !== undefined;
}


function makeNoise(animal: Cat | Dog): string {
    if(isCat(animal)) {
        // animal; // Hover this
        return "Meow";
    } else {
        // animal; // Hover this
        return "Bhaw";
    }
}

Check any library supporting typescript and you will find types and typings in package.json refers to type definitions in package.json for typescript.

Make sure to put types in devDependencies.

You can search for a library whether it is having its own type definition package or not on typescriptlang official site.

Modules

If you have two files without having export and it will work as everything declared inside the file will be global scoped which make it a script. As soon as you write export before a function or variable, it turns into module based.

If you are having script based files then files should be included in order in tsconfig.json.

In tsconfig.json file, module key is nothing but which module type it should consider after compiling. Like change it to ES6 as commonjs wont work in browser when js is generated. module is target module system.

Now, if you want to run in browser then specify type.

<script type="module" src="./index.js"></script>

If you want to import type definitions then do following, which is guaranteed to be removed from compiled js code:

import type { Person } from './types.js';

Typescript.pdf

⚠️ **GitHub.com Fallback** ⚠️