Generics Flashcards
*
Q: What is a generic function and how do you create one in TypeScript?
A: A generic function is one that can work with multiple types while maintaining type safety. It uses type variables (usually T or Type) to capture the type information.
function identity<Type>(arg: Type): Type { return arg; } // Usage: let output = identity<string>("myString"); // Or with type inference: let output = identity("myString");
Q: How do you work with generic type variables and array types?
A: When working with generic type variables, you can specify additional type information about the structure you expect.
// Working with arrays of generic type function loggingIdentity<Type>(arg: Type[]): Type[] { console.log(arg.length); return arg; } // Alternative syntax function loggingIdentity<Type>(arg: Array<Type>): Array<Type> { console.log(arg.length); return arg; }
Q: How do you create and use generic interfaces in TypeScript?
A: Generic interfaces can be created in two ways: with a generic call signature or with the interface itself being generic.
// Generic call signature interface GenericIdentityFn { <Type>(arg: Type): Type; } // Generic interface interface GenericIdentityFn<Type> { (arg: Type): Type; } let myIdentity: GenericIdentityFn<number> = identity;
Q: How do you create and use generic classes in TypeScript?
A: Generic classes use type parameters in angle brackets similar to interfaces. They only work on the instance side of the class, not the static side.
class GenericNumber<NumType> { zeroValue: NumType; add: (x: NumType, y: NumType) => NumType; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function(x, y) { return x + y; };
Q: What are generic constraints and how do you use them?
A: Generic constraints allow you to limit what types can be used with a generic function or class using the ‘extends’ keyword.
interface Lengthwise { length: number; } function loggingIdentity<Type extends Lengthwise>(arg: Type): Type { console.log(arg.length); // Now we know it has a .length property return arg; } // Works with strings, arrays, or any type with length property loggingIdentity({length: 10, value: 3});
Q: How do you use generic parameter defaults in TypeScript?
A: Generic parameter defaults allow you to specify default types for generic parameters, making them optional.
interface Container<T = string> { value: T; } // No type argument needed - defaults to string let stringContainer: Container = { value: "hello" }; // Explicit type argument let numberContainer: Container<number> = { value: 123 };
Q: How do you constrain one type parameter based on another?
A: You can declare a type parameter that is constrained by another type parameter using ‘extends’ and ‘keyof’.
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) { return obj[key]; } let x = { a: 1, b: 2, c: 3 }; getProperty(x, "a"); // OK // getProperty(x, "z"); // Error: "z" is not in keyof T
Q: How do you use class types in generic functions?
A: When working with class types in generics, you typically use the constructor signature with ‘new’.
function create<Type>(c: { new(): Type }): Type { return new c(); } class BeeKeeper { hasMask: boolean = true; } class Bee { keeper: BeeKeeper = new BeeKeeper(); } const bee = create(Bee); // Returns a new Bee instance