//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 = [1, 2, 3, 4, 5, 500]; let fruits: Array = ["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): Array { 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 slide 25 & 26 /// function wrapInArray(item: T): T[] { return [item]; } const numberArray = wrapInArray(1234); const stringArray = wrapInArray("WebDev"); //console.log(numberArray) //console.log(stringArray) interface ApiResponse { status: number; success: boolean; payload: Data; } interface UserPayload { username: string; } const response: ApiResponse = { 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 makes all properties in T optional // function updateTask(task: Task, fieldsToUpdate: Partial): 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 // type CompleteTask = Required; //16.3 Readonly // type ImmutableTask = Readonly; //16.4 Pick selects a set of properties K from T type TaskPreview = Pick; //Omit removes properties K from T type TaskForm = Omit; const preview: TaskPreview = { id: 100, title: "Review Assignment" }; const formInput: TaskForm = { title: "Release 001", description: "release 001 assignment", completed: false, }; //16.5 Record construct an object map from keys K to values T // type UserRole = "admin" | "editor" | "viewer"; const permission: Record = { admin: ["read", "write", "delete"], editor: ["read", "write"], viewer: ["read"], }; // console.log(permission.editor)