function fail(arr: never): never { return new Error; } function pluck(obj: T, propertyNames: K[]): T[K][] { return propertyNames.map(key => obj[key]) } interface Author { name: string; } interface Course = { id: number; title: string; author: number; } const course: Course = { id: 123, title: 'Advanced Typescript', author: { name: 'Marek Dano' }, } pluck(course, ['name]) // error pluck(course, ['title]) // OK type Freeze = { readonly [P in keyof T]: T[P]; } const freezeObj = Freeze = course; // OR use built-in function Readonly const freezeObj = Readonly = course; freezeObj.title = ''; // error - can't change property interface Mentor { readonly name: string; readonly course: Course; } type Writable = { [P in K]: T[P] } const writableMentor: Writable = {name: 'davy', course}; writableMentor.course = course; // works OK // OR use type Writable = { -readonly [P in keyof T]: T[P]; } const writableMentor: Writable = {name: 'davy', course}; writableMentor.course = course; // works OK // Overloading functions export function findCourse(name: string): Course[]; export function findCourse(id: number): Course[]; // above this can be replaced by export function findCourse (args: T): Course[]; export function findCourse (author: Author): Course[]; export function find(args: T): U[] // example of using generics export function findCourse(searchTerm: number | string | Author): Course[] { if (typeof searchTerm === 'string') { return courses.filter(course => course.title === searchTerm); } if (typeof searchTerm === 'number') { return courses.filter(course => course.id === searchTerm); } return courses.filter(course => course.author.name.includes(searchTerm)); } findCourse(123); findCourse('Advanced Typescript'); // conditional type below type NoNullable = T extends null | undefined ? never : T; function transform(text: T): T extends string ? string : null; function transform(text: string | null): string | null { return text && text.replace(/f/g, 'p'); } interface Cat {} interface Lion {} interface Sharp { swim: boolean; } type Animal = Cat | Lion | Shark; type ExtractFish = A extends { swim: boolean } ? A : never; type Fish = ExtractFish;