- Error checking at compile time. So less testing like unit test
- Type checking, Code Completion, Refactoring, New features
Transpilation: .ts --> Com;iler --> .js
npm i -g typescript
tsc -v // Version 5.8.3let num1: number = 20;tsc index.tsThis command create index.js
var num1 = 20;tsc --initSee some options. If we remove es2016 and press ctrl+space we can see all options
"target": "es2016",
"module": "commonjs",
"rootDir": "./", // "rootDir": "./src",
"outDir": "./dist",
"removeComments": true,
"noEmitOnError": true,Now if we run "tsc" in terminal, typescript compiler will complile all file in this project.
let firstName: string = "Dylan";Explicit type assignment are easier to read and more intentional. Note: Having TypeScript "guess" the type of a value is called infer.
- Error
let firstName: string = "Dylan"; // type string
firstName = 33; // attempts to re-assign the value to a different typeThrow error
let firstName = "Dylan"; // inferred to type string
firstName = 33; // attempts to re-assign the value to a different type-
Type: any
-
Type: unknown
-
any Purpose: Opt-out of type checking
Behavior:
Allows assignment of any value Allows access to any property/method without type checking Essentially turns off TypeScript's type system for the variable
let anything: any = "hello";
anything = 42; // OK
anything = true; // OK
anything.nonExistentMethod(); // No error (runtime error possible)- unknown Purpose: Type-safe counterpart of any
Behavior:
- Can hold any value (like any)
- Cannot be used directly without type checking or type assertion
- Forces you to validate the type before using it
let uncertain: unknown = "hello";
// These would cause errors:
// uncertain.toUpperCase();
// let str: string = uncertain;
// Proper usage:
if (typeof uncertain === "string") {
uncertain.toUpperCase(); // OK
}
// Or with type assertion:
(uncertain as string).toUpperCase();const names: string[] = [];
names.push("Subroto"); // no error
// names.push(3); // Error: Argument of type 'number' is not assignable to parameter of type 'string'.TypeScript can infer the type of an array if it has values.
const numbers = [1, 2, 3]; // inferred to type number[]
numbers.push(4); // no error
// comment line below out to see the successful assignment
numbers.push("2"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.
let head: number = numbers[0]; // no error// define our tuple
let ourTuple: [number, boolean, string];
// initialize correctly
ourTuple = [5, false, "Coding God was here"];TypeScript has a specific syntax for typing objects.
const car: { type: string, model: string, year: number } = {
type: "Toyota",
model: "Corolla",
year: 2009,
};Object types like this can also be written separately, and even be reused, achiving by interfaces.
TypeScript allows types to be defined separately from the variables that use them. Aliases and Interfaces allows types to be easily shared between different variables/objects.
Type Aliases allow defining types with a custom name (an Alias).
Type Aliases can be used for primitives like string or more complex types such as objects and arrays:
type CarYear = number;
type CarType = string;
type CarModel = string;
type Car = {
year: CarYear,
type: CarType,
model: CarModel,
};
const carYear: CarYear = 2001;
const carType: CarType = "Toyota";
const carModel: CarModel = "Corolla";
const car: Car = {
year: carYear,
type: carType,
model: carModel,
};Interfaces are similar to type aliases, except they only apply to object types.
interface Rectangle {
height: number;
width: number;
}
const rectangle: Rectangle = {
height: 20,
width: 10,
};interface Rectangle {
height: number;
width: number;
}
interface ColoredRectangle extends Rectangle {
color: string;
}
const coloredRectangle: ColoredRectangle = {
height: 20,
width: 10,
color: "red",
};TypeScript has a specific syntax for typing function parameters and return values.
The : number here specifies that this function returns a number
function getTime(): number {
return new Date().getTime();
}If no return type is defined, TypeScript will attempt to infer it through the types of the variables or expressions returned.
The type void can be used to indicate a function doesn't return any value.
function printHello(): void {
console.log("Hello!");
}Function parameters are typed with a similar syntax as variable declarations.
function multiply(a: number, b: number) {
return a * b;
}If no parameter type is defined, TypeScript will default to using any, unless additional type information is available as in the Default Parameters.
By default TypeScript will assume all parameters are required, but they can be explicitly marked as optional.
The ? operator here marks parameter c as optional
function add(a: number, b: number, c?: number) {
return a + b + (c || 0);
}For parameters with default values, the default value goes after the type annotation:
function pow(value: number, exponent: number = 10) {
return value ** exponent;
}Typing named parameters follows the same pattern as typing normal parameters.
function divide({ dividend, divisor }: { dividend: number, divisor: number }) {
return dividend / divisor;
}Rest parameters can be typed like normal parameters, but the type must be an array as rest parameters are always arrays.
function add(a: number, b: number, ...rest: number[]) {
return a + b + rest.reduce((p, c) => p + c, 0);
}Casting with as A straightforward way to cast a variable is using the as keyword, which will directly change the type of the given variable.
let x: unknown = 'hello';
console.log((x as string).length);Casting doesn't actually change the type of the data within the variable, for example the following code will not work as expected since the variable x is still holds a number.
let x: unknown = 4;
console.log((x as string).length); // prints undefined since numbers don't have a lengthGenerics makes it easier to write reusable code.
Generics with functions help make more generalized methods which more accurately represent the types used and returned.
function createPair<S, T>(v1: S, v2: T): [S, T] {
return [v1, v2];
}
console.log(createPair < string, number > ("hello", 42)); // ['hello', 42]Generics can be used to create generalized classes, like Map.
class NamedValue<T> {
private _value: T | undefined;
constructor(private name: string) {}
public setValue(value: T) {
this._value = value;
}
public getValue(): T | undefined {
return this._value;
}
public toString(): string {
return `${this.name}: ${this._value}`;
}
}
let value = new NamedValue<number>('myNumber');
value.setValue(10);
console.log(value.toString()); // myNumber: 10