// No TypeScript function add(a, b) { return a + b; } // Type function arguments // vvvvvv vvvvvv function add(a: number, b: number) { return a + b; } // Type return statement // vvvvvv function add(a: number, b: number): number { return a + b; } // Accept number or string // vvvvvvvvvvvvvvv vvvvvvvvvvvvvvv vvvvvvvvvvvvvvv function add(a: number | string, b: number | string): number | string { return a + b; } // That's a bit silly... // a and b should both be numbers or strings, don't mix! // Introduce a generic type T that represents number or string // // This will effectively result in: // (a: number, b: number): number // OR // (a: string, b: string): string // vvvvvvvvvvvvvvvvvvvvvvvvv function add(a: T, b: T): T { return a + b; } // Think of generic types () as type variables! // Return an object with the result // vvvvvvvvvvvvv function add(a: T, b: T): { result: T } { return { result: a + b }; } // Make that type "reusable" // Notice how we're passing that generic type into the interface interface ResultObject { result: T; } // vvvvvvvvvvvvvvv function add(a: T, b: T): ResultObject { // The interface ensures that what we return fits the // ResultObject interface return { result: a + b }; } // Now you know enough to be dangerous ☢️