Generics
50 bites tagged Generics — interview questions with model answers, and 60-second explainers.
Write a generic ApiResponse<T> type with success and error states
Define two interfaces sharing a status literal, one with data: T and the other with error: { code; message; }. modeling exclusive states with discriminated unions and generics.
Create a generic getProperty using generics and keyof
Whether you can constrain a generic key with keyof and return the exact property type. Use T for the object and K extends keyof T for the key, returning T[K]. Using string for the key allows invalid properties and erases the return type.
What are Swift generics, why useful, and write a swap function?
This tests parametric polymorphism and type-safe reuse. A strong answer defines generics as placeholder types for reusable code, then writes a swap<T> function using inout parameters. Red flag: confusing generics with Any or omitting inout.
Swift Existential Types: The Polymorphism Box
An existential type is a boxed protocol: you see the interface, not the concrete type inside. Use it to store mixed concrete types behind one protocol, like [any Logger]. Prefer generics; existentials hide types and add dynamic dispatch overhead.
Explain Go's empty interface, safe usage, and runtime risks
Interface{} (alias any) holds values; unpack with type switches or ok assertions; risks are panics from bare assertions and nil interface vs nil concrete value confusion. Go's universal value box and type erasure.
Design a type-safe polymorphic component that renders as different HTML elements
Tests TypeScript generics and prop forwarding in design systems. Answer: generic as constrained to keyof JSX.IntrinsicElements, merged with ComponentPropsWithoutRef<C>, omit clashes, forward ref with ElementRef.
What is a reified type parameter in Kotlin?
Tests JVM type erasure and inline function mechanics. Strong answer: reified preserves generic types at runtime via inline expansion, enabling is T checks without Class<T> passing. Red flag: claiming reified works without inline or outside functions.
Explain Kotlin's declaration-site variance with in and out
Out T means covariant producer (read), in T means contravariant consumer (write), removing wildcard noise. Understanding declaration-site variance versus wildcards. Confusing in/out with bounds or claiming immutability.
What is a reified type parameter in Kotlin?
Tests your grasp of JVM type erasure and Kotlin's solution. Explain that `reified` makes a generic type accessible at runtime inside an `inline` function, avoiding manual `Class` passing. A red flag is failing to link `reified` directly to `inline` functions.
Explain Kotlin's declaration-site variance with `in` and `out`
This tests your grasp of type systems and API design. Explain how `out` (covariance/producer) and `in` (contravariance/consumer) provide type safety at the declaration site, simplifying usage. A red flag is confusing variance with immutability.
Explain Kotlin's `reified` type parameters and their use case
Tests your grasp of JVM type erasure and Kotlin's solution. A great answer defines `reified` as making a generic type's Class accessible at runtime, explains this requires an `inline` function to substitute the type at the call site, and shows an example.
Explain Kotlin's declaration-site variance with in and out
This tests your grasp of generic type safety and API design. Explain that `out` marks covariant producers (e.g., `List<out E>`) and `in` marks contravariant consumers, then contrast this cleaner declaration-site model with Java's repetitive use-site wildcards.
Variadic Tuple Types: Type-Safe Spreads for Tuples
Variadic tuple types let you use spread syntax (`...`) inside tuple type definitions, just like you do with array values. This is crucial for typing functions that manipulate tuples, like `concat`, without writing endless overloads or losing type information.
TypeScript `infer`: Create a Self-Typing Fetch Wrapper
Use TypeScript's `infer` to build one fetch wrapper that automatically knows the correct request/response types for every endpoint. It's essential for type-safe calls to APIs with a defined schema.
TypeScript Generics: Writing Functions That Adapt to Types
TypeScript generics create functions with type placeholders, capturing an input's type to inform the output's. This is vital for reusable components that work on various data types.
Conditional Types: Ternary Logic for Your Types
Conditional types are like a ternary operator for your type system, choosing a type based on a condition (`T extends U ? X : Y`). They're used with generics to make a function's return type depend on its input, avoiding cumbersome function overloads.
keyof: A Union Type of an Object's Keys
`keyof` is like `Object.keys()` for the type system, creating a union type of an object's property names. It's used to write generic functions that safely access properties on unknown objects.
Associated Types: Making Protocols Generic
Associated types make protocols generic. Think of them as a "fill-in-the-blank" type name. A protocol like `Sequence` has an `Element` type, which a conforming `Array<String>` fills in as `String`.
Rust Const Generics: Parameterize by Value, Not Just Type
Const generics let Rust types be parameterized by values, not just other types. This allows writing code generic over array sizes, like `Matrix<T, const N: usize>`, ensuring dimensions are checked at compile time.
Rust Associated Types: One Trait, One Concrete Type
Associated types link a placeholder type to a trait, ensuring any implementation provides one specific type. This cleans up code, like in Rust's `Iterator` trait. The footgun: a type can only implement a trait with an associated type once.
Rust's `impl Trait`: Hiding Concrete Types
Rust's `impl Trait` specifies a type by its behavior, not its name. Use it in function arguments for cleaner generics (`fn f(x: impl Debug)`) or in return types to hide complex types like closures and iterators, avoiding heap allocation.
Static Dispatch: Zero-Cost Abstraction via Monomorphization
Static dispatch resolves function calls at compile time, avoiding runtime overhead. Rust does this via monomorphization, creating specialized code for each concrete type. This is the default for generics, but the trade-off is larger binary sizes.
Rust Traits: Defining Shared Behavior
Rust traits are like contracts that guarantee a type has certain methods, similar to interfaces. This lets you write functions that operate on any type with that behavior, like a `summarize` method for both articles and posts.
Dart Generics: Type-Safe Containers and Reusable Code
Generics let you define code that works with multiple types without sacrificing type safety. A `List<String>` is a list that only accepts strings. This is essential for collections.
Get Generics bites daily.
Five a day, five minutes, offline. With quizzes so it sticks.
Open testing — you’ll join as an early tester.