Typescript Notes
Typescript Notes
Types of variables:
Primitives:
boolean;
number;
string;
void, null, undefined;
Function
array
OtherTypes:
Any
unknown
Enums: An enum, is a symbolic name for a set of values. Enumerations are treated as data types, and
you can use them to create sets of constants for use with variables and properties.
enum ContractStatus {
Permanent,
Temp,
Apprentice
}
enum ContractStatus {
Permanent = 1,
Temp,
Apprentice
}
Examples:
Example1:
Example2:
interface Employee {
employeeID: number;
age: number;
}
interface Manager {
stockPlan: boolean;
}
type ManagementEmployee = Employee & Manager;
Literal types
A literal is a more concrete subtype of a collective type. What this means is
that "Hello World" is a string, but a string is not "Hello World" inside the type
system.
There are three sets of literal types available in TypeScript: string, number,
and boolean. By using literal types, you can specify an exact value that a
string, number, or boolean must have (for example, "yes", "no", or "maybe".)
LITERAL NARROWING: Using const instead of let or var. Shrinks the scope of
the variable since it will either change whenever either to never change. This
process is called literal narrowing (reducing to a finite number of use cases
by changing literals)
Example1:
Example2:
type dice = 1 | 2 | 3 | 4 | 5 | 6;
let diceRoll: dice;
diceRoll = 1; //* Valid
diceRoll = 2; //* Valid
diceRoll = 7; //* Invalid
Collection Types
Arrays
TypeScript, like JavaScript, allows you to work with arrays. Arrays can be
written in one of two ways. In the first, you use the type of the elements
followed by square brackets ([ ]) to denote an array of that element type:
Tuples
Having an array of the same value types is useful, but sometimes you have
an array that contains values of mixed types. For that purpose, TypeScript
provides the Tuple type. To declare a Tuple, use the syntax variableName:
[type, type, ...].
INTERFACES
What is an interface
You can use interfaces to describe an object, naming and parameterizing the object's types,
and to compose existing named object types into new ones.
This simple interface defines the two properties and a method of an Employee object.
interface Employee {
firstName: string;
lastName: string;
fullName(): string;
}
Notice that the interface doesn't initialize or implement the properties declared within it.
That's because the only job of an interface is to describe a type.
Drive consistency across a set of objects because every object that implements the
interface operates under the same type definitions. This can be useful when you're
working with a team of developers and you want to ensure that proper values are being
passed into properties, constructors, or functions. For example, objects that implement an
interface must implement all the required members of the interface. So, if you don't pass
all the required parameters of the correct type, the TypeScript compiler will throw an
error.
Describe existing JavaScript APIs and clarify function parameters and return types. This is
especially useful when you're working with JavaScript libraries like jQuery. An interface
can provide you with a clear understanding of what a function is expecting and what it
will return without repeat visits to the documentation.
typeEmployee = {
firstName: string;
lastName: string;
fullName(): string;
}
A type alias is a definition of a type of data, for example, a union, primitive, intersection, tuple, or
any other type. Interfaces, on the other hand, are a way to describe data shapes, for example, an
object. Type aliases can act like interfaces; however, there are some subtle differences. The key
distinction is that a type alias cannot be reopened to add new properties whereas an interface is
always extendable.
Extend an interface
There are several types of desserts you can create from the IceCream interface (sundaes,
milkshakes, and so on), but they all have different properties in addition to those declared
in IceCream. Let's extend the interface with a new one called Sundae and declare its properties.
interface IceCreamArray {
[index: number]: string;
}
let myIceCream: IceCreamArray;
myIceCream = ['chocolate', 'vanilla', 'strawberry'];
let myStr: string = myIceCream[0];
console.log(myStr);
The fetch API is a native JavaScript function that you can use to interact with web services. This
example declares an interface called Post for the return types in a JSON file and then
uses fetch with async and await to generate a strongly typed response.
Functions
Named functions
The syntax for declaring a named function in TypeScript is the same as defining one in JavaScript.
The only difference with TypeScript is that you can provide a type annotation for the function's
parameters and return value.
Anonymous functions
Function expressions represent values so they are usually assigned to a variable or passed to
other functions, and can be anonymous, meaning the function has no name.
This example assigns a function expression to the variable addNumbers. Notice that function
appears in place of the function name, making the function anonymous. You can now use this
variable to call the function.
Arrow functions
Arrow functions (also called Lambda or fat arrow functions because of the => operator used to
define them) provide shorthand syntax for defining an anonymous function. Due to their concise
nature, arrow functions are often used with simple functions and in some event handling
scenarios.
// Arrow function
let addNumbers2 = (x: number, y: number): number => x + y;
Required parameters
All function parameters are required, unless otherwise specified, and the number of arguments
passed to a function must match the number of required parameters the function expects.
Default parameters
You can also assign default values to optional parameters. If a value is passed as an argument to
the optional parameter, that value will be assigned to it. Otherwise, the default value will be
assigned to it. As with optional parameters, default parameters must come after required
parameters in the parameter list.
Rest Parameters
If you want to work with multiple parameters as a group (in an array) or don't know how many
parameters a function will ultimately take, you can use rest parameters. Rest parameters are
treated as a boundless number of optional parameters. You may leave them off or have as many
as you want.
Example1:
// Alternative
interface Calculator {
(x: number, y: number): number; //Notation is slightly different
}
Classes in Typescript
Example of Class with typed properties:
class Car {
constructor(make: string, color: string, doors = 4){
this._make = make;
this._color = color;
this._doors = doors;
Car.numberOfCars++; // Increments the value of the static property
}
//typed for class
private static numberOfCars: number = 0; // New static property
_make: string;
_color: string;
_doors: number;
get make() {
return this._make;
}
set make(make) {
this._make = make;
}
get color() {
return 'The color of the car is ' + this._color;
}
set color(color) {
this._color = color;
}
get doors() {
return this._doors;
}
set doors(doors) {
if ((doors % 2) === 0) {
this._doors = doors;
} else {
throw new Error('Doors must be an even number');
}
}
// Methods
accelerate(speed: number): string {
return `${this.worker()} is accelerating to ${speed} MPH.`
}
brake(): string {
return `${this.worker()} is braking with the standard braking system.`
}
turn(direction: 'left' | 'right'): string {
return `${this.worker()} is turning ${direction}`;
}
// This function performs work for the other method functions
worker(): string {
return this._make;
}
}
Static Properties:
o make a property static, use the static keyword before a property or
method name.
For example, you can add a new static property to the Car class
called numberOfCars that stores the number of times that the Car class
is instantiated and set its initial value to 0. Then, in the constructor,
increment the count by one.
Notice that you use the syntax className.propertyName instead
of this. when accessing the static property.
You can also define static methods. You can call
the getNumberOfCars method to return the value of numberOfCars.
interface Vehicle {
make: string;
color: string;
doors: number;
accelerate(speed: number): string;
brake(): string;
turn(direction: 'left' | 'right'): string;
}
How to implement the interface within the class:
Design considerations
Interfaces are a TypeScript design-time construct. Because JavaScript
does not have a concept of interfaces, they are removed when
TypeScript is transpiled to JavaScript. This means they are completely
weightless, take up no space in the resulting file, and have no negative
impact on the code that will be executed.
Generics:
Generics are code templates that you can define and reuse throughout
your codebase. They provide a way to tell functions, classes, or
interfaces what type you want to use when you call it. You can think
about this in the same way that arguments are passed to a function,
except a generic enables you to tell the component what type it should
expect at the time it's called.
Example:
The getArray function generates an array of items of any type. First definition is:
BAD: ❌
function getArray(items : any[]) : any[] {
Instantiation:
The identity function can accept any type that you choose to pass to the
type variables. But, in this case, you should constrain the types that
the value parameter can accept to a range of types that you can
perform an add operation on, rather than accepting any possible type.
This is called a generic constraint. There are several ways to do this
depending on the type variable. One way is to declare a custom type as
a tuple and then extend the type variable with the custom type. The
following example declares ValidTypes as a tuple with a string and
a number. Then, it extends T with the new type. Now, you can only
pass number or string types to the type variable.
''
You can only use a typeof type guard to check the primitive
types string, number, bigint, function, boolean, symbol, object, and undefined. To check the type
of a class, use an instanceof type guard.
''
Implement generics with custom types and
classes
Using generics with primitive types, like number, string, or boolean,
illustrate the concepts of generics well, but the most powerful uses
come from using them with custom types and classes.This example has
a base class called Car and two subclasses, ElectricCar and Truck.
The accelerate function accepts a generic instance of Car and then
returns it. By telling the accelerate function that T must extend Car,
TypeScript knows which functions and properties you can call within the
function. The generic also returns the specific type of car
(ElectricCar or Truck) passed into the function, rather than a non-
specific Car object.
class Car {
make: string = 'Generic Car';
doors: number = 4;
}
TypeScript namespaces
Namespaces (referred to as "internal modules" in earlier versions of
TypeScript) are a TypeScript-specific way to organize and categorize
your code, enabling you to group related code together. Namespaces
allow you to group variables, functions, interfaces, or classes related to
business rules in one namespace and security in another.
Example"
namespace AllGreetings {
AllGreetings.Greetings.returnGreeting('Bonjour'); // OK
AllGreetings.GreetingsWithLength.returnGreeting('Hola'); // OK
Other Example:
Module Namespace
Use modules to organize code into Use namespaces to organize code
separate files for logical grouping of into separate files for logical
functionality. grouping of functionality.
Modules execute in their local scope, not Namespaces execute in their local
in the global scope. scope, not in the global scope.
Modules are declarative; the Namespaces cannot declare their
relationships between modules are dependencies.
specified in terms of imports and exports
at the file level.
You define a module by using either You define a namespace by using
the export or import keyword within a file. the namespace keyword within a file.
Any file containing a top-level import or Namespace statements can be
export is considered a module. nested and span multiple files.
To expose individual module components To expose individual namespace
outside the module, use components outside of the
the export keyword. namespace, use
the export keyword.
To use a component from one module in To use a component from one
another module, use the import keyword. namespace in another TypeScript
file, add a reference statement using
the triple-slash (///) syntax.
To compile a module and all its To compile TypeScript files
dependent files, use the tsc -- containing namespaces and all
module command. their dependent files into individual
JavaScript files, use
the tsc command.
It is not possible to have multi-file To compile all TypeScript files
modules compiled to a single module. containing namespaces into a
single JavaScript file, use the tsc --
outFile command.