Types
const isFetching: boolean = true
const isLoading: boolean = false
const int: number = 42
const float: number = 4.2
const num: number = 3e10
const message: string = 'Hello Typescript'
const numberArray: number[] = [1, 1, 2, 3, 5, 8, 13]
const numberArray2: Array<number> = [1, 1, 2, 3, 5, 8, 13]
const words: string[] = ['Hello', 'Typescript']
// Tuple
const contact: [string, number] = ['Audrius', 1234567]
// Any
let variable: any = 42
// ...
variable = 'New String'
variable = []
// ====
function sayMyName(name: string): void {
console.log(name)
}
sayMyName('Audrius')
// Never
function throwError(message: string): never {
throw new Error(message)
}
function infinite(): never {
while (true) {
}
}
// Type
type Login = string
const login: Login = 'admin'
// const login2: Login = 2
type ID = string | number
const id1: ID = 1234
const id2: ID = '1234'
// const id3: ID = true
type SomeType = string | null | undefined
});
Interfaces
interface Rect {
readonly id: string;
color?: string;
size: {
width: number;
height: number;
};
}
const rect1: Rect = {
id: "1234",
size: {
width: 20,
height: 30,
},
color: "#ccc",
};
const rect2: Rect = {
id: "12345",
size: {
width: 10,
height: 5,
},
};
rect2.color = "black";
// rect2.id = '3232'
const rect3 = {} as Rect;
const rect4 = <Rect>{};
// =====================
interface RectWithArea extends Rect {
getArea: () => number;
}
const rect5: RectWithArea = {
id: "123",
size: {
width: 20,
height: 20,
},
getArea(): number {
return this.size.width * this.size.height;
},
};
// ==================
interface IClock {
time: Date;
setTime(date: Date): void;
}
class Clock implements IClock {
time: Date = new Date();
setTime(date: Date): void {
this.time = date;
}
}
// =================
interface Styles {
[key: string]: string;
}
const css: Styles = {
border: "1px solid black",
marginTop: "2px",
borderRadius: "5px",
};
Enum
enum Membership {
Simple,
Standard,
Premium,
}
const membership = Membership.Standard;
const membershipReverse = Membership[2];
console.log(membership);
console.log(membershipReverse);
enum SocialMedia {
FACEBOOK = "FACEBOOK",
INSTAGRAM = "INSTAGRAM",
}
const social = SocialMedia.INSTAGRAM;
console.log(social);
Functions
function add(a: number, b: number): number {
return a + b;
}
function toUpperCase(str: string): string {
return str.trim().toUpperCase();
}
interface MyPosition {
x: number | undefined;
y: number | undefined;
}
interface MyPositionWithDefault extends MyPosition {
default: string;
}
function position(): MyPosition;
function position(a: number): MyPositionWithDefault;
function position(a: number, b: number): MyPosition;
function position(a?: number, b?: number) {
if (!a && !b) {
return { x: undefined, y: undefined };
}
if (a && !b) {
return { x: a, y: undefined, default: a.toString() };
}
return { x: a, y: b };
}
console.log("Empty: ", position());
console.log("One param: ", position(42));
console.log("Two params: ", position(10, 15));
Classes
class Typescript {
version: string;
constructor(version: string) {
this.version = version;
}
info(name: string) {
return `[${name}]: Typescript version is ${this.version}`;
}
}
// class Car {
// readonly model: string
// readonly numberOfWheels: number = 4
//
// constructor(theModel: string) {
// this.model = theModel
// }
// }
class Car {
readonly numberOfWheels: number = 4;
constructor(readonly model: string) {}
}
// ==============
class Animal {
protected voice: string = "";
public color: string = "black";
constructor() {
this.go();
}
private go() {
console.log("Go");
}
}
class Cat extends Animal {
public setVoice(voice: string): void {
this.voice = voice;
}
}
const cat = new Cat();
cat.setVoice("test");
console.log(cat.color);
// cat.voice
// =====================
abstract class Component {
abstract render(): void;
abstract info(): string;
}
class AppComponent extends Component {
render(): void {
console.log("Component on render");
}
info(): string {
return "This is info";
}
}
Guards
function strip(x: string | number) {
if (typeof x === "number") {
return x.toFixed(2);
}
return x.trim();
}
class MyResponse {
header = "response header";
result = "response result";
}
class MyError {
header = "error header";
message = "error message";
}
function handle(res: MyResponse | MyError) {
if (res instanceof MyResponse) {
return {
info: res.header + res.result,
};
} else {
return {
info: res.header + res.message,
};
}
}
// ===================
type AlertType = "success" | "danger" | "warning";
function setAlertType(type: AlertType) {
// ....
}
setAlertType("success");
setAlertType("warning");
// setAlertType('default')
Operators
interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // 'name' | 'age'
let key: PersonKeys = "name";
key = "age";
type User = {
_id: number;
name: string;
email: string;
createdAt: Date;
};
// 'name' | 'email'
type UserKeysNoMeta1 = Exclude<keyof User, "_id" | "createdAt">;
// 'name' | 'email'
type UserKeysNoMeta2 = Pick<User, "name" | "email">;
let u1: UserKeysNoMeta1 = "name";
// u1 = '_id'
Generics
const arrayOfNumbers: Array<number> = [1, 1, 2, 3, 5];
const arrayOfStrings: Array<string> = ["Hello", "Audrius"];
function reverse<T>(array: T[]): T[] {
return array.reverse();
}
reverse(arrayOfNumbers);
reverse(arrayOfStrings);
// const cars: string[] = ['Ford', 'Audi']
// const cars2: Array<string> = ['Ford', 'Audi']
// const promise: Promise<number> = new Promise(resolve => {
// setTimeout(() => {
// resolve(42)
// }, 2000)
// })
//
// promise.then(data => {
// console.log(data.toFixed())
// })
function mergeObjects<T extends object, R extends object>(a: T, b: R) {
return Object.assign({}, a, b);
}
const merged = mergeObjects({ name: "Audrius" }, { age: 26 });
const merged2 = mergeObjects({ model: "Ford" }, { year: 2010 });
// const merged3 = mergeObjects({a: 1}, 'bbb')
// console.log(merged3)
// =================
interface ILength {
length: number;
}
function withCount<T extends ILength>(value: T): { value: T; count: string } {
return {
value,
count: `Object has ${value.length} symbols`,
};
}
// console.log(withCount('Hi typescript'))
// console.log(withCount(['I', 'Am', 'Array']))
// console.log(withCount(20))
// console.log(withCount({length: 20}))
// ==============
// function getObjectValue<T extends object, R extends keyof T>(obj: T, key: R) {
// return obj[key]
// }
//
// const person = {
// name: 'Audrius',
// age: 26,
// job: 'Javascript'
// }
// console.log(getObjectValue(person, 'name'))
// console.log(getObjectValue(person, 'age'))
// console.log(getObjectValue(person, 'job'))
// ===============
class Collection<T extends number | string | boolean> {
constructor(private _items: T[] = []) {}
add(item: T) {
this._items.push(item);
}
remove(item: T) {
this._items = this._items.filter((i) => i !== item);
}
get items(): T[] {
return this._items;
}
}
// const strings = new Collection<string>(['I', 'Am', 'Strings'])
// strings.add('!')
// strings.remove('Am')
// console.log(strings.items)
//
// const numbers = new Collection<number>([1, 2, 3])
// numbers.add(2)
// numbers.remove(3)
// console.log(numbers.items)
// const objs = new Collection([{a: 1}, {b: 2}])
// // objs.remove({b: 2})
// // console.log(objs.items)
// ===============
interface Car {
model: string;
year: number;
}
function createAndValidateCar(model: string, year: number): Car {
const car: Partial<Car> = {};
if (model.length > 3) {
car.model = model;
}
if (year > 2000) {
car.year = year;
}
return car as Car;
}
///
const cars: Readonly<Array<string>> = ["Ford", "Audi"];
// cars.shift()
// cars[1]
const ford: Readonly<Car> = {
model: "Ford",
year: 2020,
};
// ford.model = 'Ferrari'
Decorators
// function Log(constructor: Function) {
// console.log(constructor)
// }
//
// function Log2(target: any, propName: string | Symbol) {
// console.log(target)
// console.log(propName)
// }
//
// function Log3(target: any, propName: string | Symbol, descriptor: PropertyDescriptor) {
// console.log(target)
// console.log(propName)
// console.log(descriptor)
// }
// interface ComponentDecorator {
// selector: string
// template: string
// }
//
// function Component(config: ComponentDecorator) {
// return function
// <T extends { new(...args: any[]): object } >
// (Constructor: T) {
// return class extends Constructor {
// constructor(...args: any[]) {
// super(...args)
//
// const el = document.querySelector(config.selector)!
// el.innerHTML = config.template
// }
// }
// }
// }
//
// function Bind(_: any, _2: any, descriptor: PropertyDescriptor): PropertyDescriptor {
// const original = descriptor.value
//
// return {
// configurable: true,
// enumerable: false,
// get() {
// return original.bind(this)
// }
// }
// }
//
// @Component({
// selector: '#card',
// template: `
// <div class="card">
// <div class="card-content">
// <span class="card-title">Card Component</span>
// </div>
// </div>
// `
// })
// class CardComponent {
// constructor(public name: string) {
// }
//
// @Bind
// logName(): void {
// console.log(`Component Name: ${this.name}`)
// }
// }
//
// const card = new CardComponent('My Card Component')
//
// const btn = document.querySelector('#btn')!
//
// btn.addEventListener('click', card.logName)
// ================
type ValidatorType = "required" | "email";
interface ValidatorConfig {
[prop: string]: {
[validateProp: string]: ValidatorType;
};
}
const validators: ValidatorConfig = {};
function Required(target: any, propName: string) {
validators[target.constructor.name] = {
...validators[target.constructor.name],
[propName]: "required",
};
}
function validate(obj: any): boolean {
const objConfig = validators[obj.constructor.name];
if (!objConfig) {
return true;
}
let isValid = true;
Object.keys(objConfig).forEach((key) => {
if (objConfig[key] === "required") {
isValid = isValid && !!obj[key];
}
});
return isValid;
}
// class Form {
// @Required
// public email: string | void
//
// constructor(email?: string) {
// this.email = email
// }
// }
//
// const form = new Form('[email protected]')
//
// if (validate(form)) {
// console.log('Valid: ', form)
// } else {
// console.log('Validation Error')
// }
//
Namespaces
// form-namespace.ts
namespace Form {
export type FormType = "inline" | "block";
export type FormState = "active" | "disabled";
export interface FormInfo {
type: FormType;
state: FormState;
}
}
/// <reference path="form-namespace.ts" />
namespace Form {
class MyForm {
private type: FormType = "inline";
private state: FormState = "active";
constructor(public email: string) {}
getInfo(): FormInfo {
return {
type: this.type,
state: this.state,
};
}
}
export const myForm = new MyForm("[email protected]");
}
console.log(Form.myForm);
// console.log(myForm)