Typescript - deependhamecha/angular GitHub Wiki
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 totsconfig.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.
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.
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
}
}
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();
});
function dude(str: string='DEFAULT', n: number) {
}
dude(1); // Error
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.
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
}
};
type Dog = {
bark: boolean
}
type Cat = {
meow: boolean;
}
type CatDog = Cat | Dog;
var catdog: CatDog = {meow: true};
type DayOfWeek = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday";
let today: DayOfWeek = "Monday";
let today: DayOfWeek = "Someday"; // Wont work
Arrays of fix length with type strictness on indexes.
let myTuple: [number, string];
myTuple = [1, 'abc'];
myTuple = ['abc', 'abc']; // Error
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.
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
};
You can create configuration file tsconfig.json
with tsc --init
/**
* 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
*/
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.
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';