328 lines
7.5 KiB
TypeScript
328 lines
7.5 KiB
TypeScript
//1. implicit type inference ///
|
|
|
|
let language = "Jeannette"; // inferred as string
|
|
let year = 2026; //inferred as number
|
|
|
|
//console.log(language)
|
|
|
|
//1.1. explicit Type annotations - slide 10 ///
|
|
let age: number = 100;
|
|
let isPresenter: boolean = true;
|
|
let emptyValue: null = null;
|
|
let notAssigned: undefined = undefined;
|
|
|
|
//1.2. type any ///
|
|
|
|
let value: any;
|
|
|
|
value = 123; // ok
|
|
value = "123"; // ok
|
|
value = true; // ok
|
|
|
|
//1.3. type union - allows a value to be one of several types, defined using the pipe (|) symbol. ///
|
|
|
|
type IDD = string | number;
|
|
|
|
function printId(id: IDD) {
|
|
// Type narrowing with typeof
|
|
if (typeof id === "string") {
|
|
console.log(`ID string in uppercase: ${id.toUpperCase()}`);
|
|
} else {
|
|
console.log(`Numeric ID multiplied: ${id * 10}`);
|
|
}
|
|
}
|
|
|
|
//printId(101); // Valid
|
|
//printId("task_abc"); // Valid
|
|
// printId(true); // Error: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.
|
|
|
|
//2. Array - slide 11///
|
|
|
|
let techStack: string[] = ["TS", "JS", "Node", "Next.js"];
|
|
|
|
let scores: Array<number> = [1, 2, 3, 4, 5, 500];
|
|
|
|
let fruits: Array<string> = ["orange", "apple", "berry"];
|
|
|
|
//console.log(techStack)
|
|
//console.log(fruits)
|
|
|
|
// what is the type of below array?
|
|
|
|
let array1 = ["CMP6057A", 6057, true];
|
|
|
|
//let array2: (string | number | boolean)[] = ["CMP6057A", 6057, true]
|
|
|
|
//2.1. tuples - fixed-length arrays where each index has a specific type
|
|
|
|
let httpStatus: [number, string] = [200, "OK"];
|
|
|
|
//console.log(httpStatus[1])
|
|
|
|
//2.2. objects //
|
|
|
|
let object: object; //ok
|
|
|
|
object = {}; // ok
|
|
object = []; // ok but why?
|
|
|
|
let user: { id: number; name: string; isAdmin?: boolean } = {
|
|
id: 1,
|
|
name: "JC",
|
|
};
|
|
|
|
//console.log(user)
|
|
|
|
//2.3. Enums : name constants ///
|
|
|
|
enum Role {
|
|
Admin = "Admin",
|
|
User = "User",
|
|
Guest = "Guest",
|
|
}
|
|
|
|
let currentRole = Role.Admin;
|
|
//console.log(currentRole)
|
|
|
|
//3. Type alias - slide 13 & 14 //
|
|
|
|
type ID = string | number;
|
|
type OrderStatus =
|
|
| "pending"
|
|
| "processing"
|
|
| "shipped"
|
|
| "delivered"
|
|
| "cancelled";
|
|
|
|
type Order = {
|
|
id: ID;
|
|
status: OrderStatus;
|
|
totalAmount: number;
|
|
};
|
|
|
|
function updateOrderStatus(orderID: ID, newStatus: OrderStatus): void {
|
|
console.log(`order ${orderID} moved to status ${newStatus}`);
|
|
}
|
|
|
|
//updateOrderStatus("order 12344", "shipped");
|
|
//updateOrderStatus("order 9999", "refunded");
|
|
|
|
/// slides for complex examples slide 15 - 17 //
|
|
|
|
///3.1. interface - slide 18 ///
|
|
|
|
interface Vehicle {
|
|
make: string;
|
|
model: string;
|
|
}
|
|
|
|
interface Car extends Vehicle {
|
|
isElectric: boolean;
|
|
}
|
|
|
|
const tesla: Car = {
|
|
make: "Tesla",
|
|
model: "Model 3",
|
|
isElectric: true,
|
|
};
|
|
|
|
//console.log(tesla);
|
|
|
|
//3.2. index signature - slide 19 //
|
|
interface OrderObj {
|
|
Banana: number;
|
|
Sugar: number;
|
|
Potato: number;
|
|
Egg: number;
|
|
Milk: number;
|
|
}
|
|
|
|
const myOrders: OrderObj = {
|
|
Banana: 3,
|
|
Sugar: 1,
|
|
Potato: 2,
|
|
Egg: 6,
|
|
Milk: 1,
|
|
};
|
|
|
|
//console.log(myOrders.Egg); //6
|
|
|
|
// const totalOrder = (orders:OrderObj):number => {
|
|
// let total = 0;
|
|
// for (const order in orders) {
|
|
// total += orders[order]
|
|
// }
|
|
|
|
// return total
|
|
// }
|
|
|
|
// console.log(totalOrder(myOrders))
|
|
|
|
///12. rest parameters - allows a function to accept any number of arguments as an array , TS ensures every passed argument matches the declared array element type - slide 20 ///
|
|
|
|
function multiply(factor: number, ...numbers: Array<number>): Array<number> {
|
|
return numbers.map((n) => n * factor);
|
|
}
|
|
|
|
//console.log(multiply(2, 1,3,5,7)) // 2,6,10,14
|
|
|
|
/// more examples //
|
|
type UserLoginArgs = [userID: number, timestamp: Date];
|
|
type SystemErrorArgs = [errorCode: number, message: string, isFatal: boolean];
|
|
|
|
function logUserLogin(...args: UserLoginArgs): void {
|
|
const [userID, timestamp] = args;
|
|
console.log(`User ${userID} logged in at ${timestamp.toISOString()}`);
|
|
}
|
|
|
|
//logUserLogin(1234, new Date())
|
|
|
|
function logSystemError(...args: SystemErrorArgs): void {
|
|
const [code, message, fatal] = args;
|
|
console.log(`Error ${code}, ${message} | Fatal: ${fatal}`);
|
|
}
|
|
|
|
//logSystemError(500, "DB Error", true);
|
|
|
|
///13. Type Never : A function has the return type never if it either always throws an error or never terminates. slide 22 & 23 ///
|
|
|
|
// Always throws an exception
|
|
function fail(message: string): never {
|
|
throw new Error(message);
|
|
}
|
|
|
|
// Runs an infinite loop
|
|
function runForever(): never {
|
|
while (true) {
|
|
// Background polling, daemon loop, etc.
|
|
}
|
|
}
|
|
|
|
///Exhaustive Type Checking (default Cases)
|
|
// The most common real-world use of never is ensuring that all members of a union are handled at compile time.
|
|
|
|
type Shape =
|
|
| { kind: "circle"; radius: number }
|
|
| { kind: "square"; side: number };
|
|
|
|
function getArea(shape: Shape): number {
|
|
switch (shape.kind) {
|
|
case "circle":
|
|
return Math.PI * shape.radius ** 2;
|
|
case "square":
|
|
return shape.side * shape.side;
|
|
default: {
|
|
// If all cases are handled, `shape` is narrowed down to `never`.
|
|
const _exhaustiveCheck: never = shape;
|
|
throw new Error(`Unhandled shape: ${_exhaustiveCheck}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
//If you later add { kind: "triangle" } to Shape without updating the switch statement, TypeScript will flag a compile-time error: Type 'Triangle' is not assignable to type 'never'. //
|
|
|
|
///14. Assertion "as" slide 24 //
|
|
|
|
// Example with unknown (e.g., from an external API or JSON.parse)
|
|
const rawData: unknown = "advanced WebDev 001 assessment";
|
|
|
|
// Without assertion, rawData.length throws an error: Object is of type 'unknown'
|
|
const titleLength = (rawData as string).length;
|
|
//console.log(titleLength); // 30
|
|
|
|
// document.getElementById returns HTMLElement | null
|
|
// HTMLInputElement gives access to .value, .checked, etc.
|
|
const inputElement = document.getElementById(
|
|
"username-input",
|
|
) as HTMLInputElement;
|
|
|
|
//console.log(inputElement.value); // Valid: value exists on HTMLInputElement
|
|
|
|
///15. Generics <T> slide 25 & 26 ///
|
|
|
|
function wrapInArray<T>(item: T): T[] {
|
|
return [item];
|
|
}
|
|
|
|
const numberArray = wrapInArray(1234);
|
|
const stringArray = wrapInArray("WebDev");
|
|
|
|
//console.log(numberArray)
|
|
//console.log(stringArray)
|
|
|
|
interface ApiResponse<Data> {
|
|
status: number;
|
|
success: boolean;
|
|
payload: Data;
|
|
}
|
|
|
|
interface UserPayload {
|
|
username: string;
|
|
}
|
|
|
|
const response: ApiResponse<UserPayload> = {
|
|
status: 200,
|
|
success: true,
|
|
payload: { username: "JC" },
|
|
};
|
|
|
|
//console.log(response.payload);
|
|
|
|
///16. utility slide26//
|
|
|
|
interface Task {
|
|
id: number;
|
|
title: string;
|
|
description: string;
|
|
completed: boolean;
|
|
}
|
|
|
|
//16.1 Partial<T> makes all properties in T optional //
|
|
|
|
function updateTask(task: Task, fieldsToUpdate: Partial<Task>): Task {
|
|
return { ...task, ...fieldsToUpdate };
|
|
}
|
|
|
|
const myTask = {
|
|
id: 123,
|
|
title: "001 assignment",
|
|
description: "advanced WebDev 001 assessment",
|
|
completed: false,
|
|
};
|
|
|
|
//updateTask(myTask, {completed:true})
|
|
//console.log(myTask) // complete = false , why?
|
|
|
|
//16.2 Required <T> //
|
|
|
|
type CompleteTask = Required<Task>;
|
|
|
|
//16.3 Readonly<T> //
|
|
|
|
type ImmutableTask = Readonly<Task>;
|
|
|
|
//16.4 Pick<T, K> selects a set of properties K from T
|
|
type TaskPreview = Pick<Task, "id" | "title">;
|
|
//Omit<T, K> removes properties K from T
|
|
type TaskForm = Omit<Task, "id">;
|
|
|
|
const preview: TaskPreview = { id: 100, title: "Review Assignment" };
|
|
|
|
const formInput: TaskForm = {
|
|
title: "Release 001",
|
|
description: "release 001 assignment",
|
|
completed: false,
|
|
};
|
|
|
|
//16.5 Record<K, T> construct an object map from keys K to values T //
|
|
|
|
type UserRole = "admin" | "editor" | "viewer";
|
|
|
|
const permission: Record<UserRole, string[]> = {
|
|
admin: ["read", "write", "delete"],
|
|
editor: ["read", "write"],
|
|
viewer: ["read"],
|
|
};
|
|
|
|
// console.log(permission.editor)
|