Bird
Raised Fist0
Typescriptprogramming~15 mins

Generic class syntax in Typescript - Deep Dive

Choose your learning style10 modes available
Overview - Generic class syntax
What is it?
Generic class syntax in TypeScript lets you create classes that work with many types instead of just one. You write the class once, and then you can use it with different data types without rewriting it. This makes your code flexible and reusable. It’s like making a blueprint that fits many shapes.
Why it matters
Without generic classes, you would need to write many versions of the same class for different data types, which is slow and error-prone. Generic classes solve this by letting you write one class that adapts to any type you choose. This saves time, reduces bugs, and makes your code easier to maintain and understand.
Where it fits
Before learning generic classes, you should know basic TypeScript classes and types. After this, you can learn about generic functions, interfaces, and advanced type constraints to write even more flexible and safe code.
Mental Model
Core Idea
A generic class is a flexible blueprint that can handle many types by using placeholders replaced with real types when used.
Think of it like...
Imagine a cookie cutter that can shape dough into any cookie shape you want by swapping the cutter’s shape. The generic class is like that cookie cutter, and the type you choose is the cookie shape.
GenericClass<T>
  ├─ property: T
  ├─ method(param: T): T
  └─ T is a placeholder for any type you pick when creating an instance
Build-Up - 7 Steps
1
FoundationBasic class structure review
🤔
Concept: Understanding how to write and use a simple class in TypeScript.
class Box { content: string; constructor(content: string) { this.content = content; } getContent() { return this.content; } } const box = new Box('apple'); console.log(box.getContent());
Result
apple
Knowing how classes work is essential before adding the flexibility of generics.
2
FoundationWhat is a generic type parameter?
🤔
Concept: Introducing the idea of a placeholder type that can be replaced later.
function identity(arg: T): T { return arg; } const result = identity(5); console.log(result);
Result
5
Understanding generic type parameters in functions prepares you to use them in classes.
3
IntermediateDefining a generic class
🤔Before reading on: do you think a generic class can have multiple type parameters or just one? Commit to your answer.
Concept: How to declare a class with a generic type parameter to make it flexible.
class Box { content: T; constructor(content: T) { this.content = content; } getContent(): T { return this.content; } } const numberBox = new Box(123); const stringBox = new Box('hello'); console.log(numberBox.getContent()); console.log(stringBox.getContent());
Result
123 hello
Knowing that generic classes let you reuse the same code for different types without rewriting it.
4
IntermediateUsing multiple type parameters
🤔Before reading on: do you think generic classes can handle more than one type at once? Commit to your answer.
Concept: Generic classes can have more than one type parameter to handle complex data.
class Pair { first: T; second: U; constructor(first: T, second: U) { this.first = first; this.second = second; } getPair(): [T, U] { return [this.first, this.second]; } } const pair = new Pair(1, 'one'); console.log(pair.getPair());
Result
[1, 'one']
Understanding multiple type parameters allows you to model more complex relationships between data.
5
IntermediateGeneric constraints with extends
🤔Before reading on: do you think generic types can be limited to certain kinds of types? Commit to your answer.
Concept: You can restrict generic types to only accept types that meet certain conditions.
interface HasLength { length: number; } class LengthBox { content: T; constructor(content: T) { this.content = content; } getLength(): number { return this.content.length; } } const box = new LengthBox('hello'); console.log(box.getLength());
Result
5
Knowing how to constrain generics prevents errors by ensuring the type has needed properties.
6
AdvancedDefault type parameters in generic classes
🤔Before reading on: do you think generic classes can have default types if none are provided? Commit to your answer.
Concept: Generic classes can provide default types to simplify usage when the type is obvious or common.
class DefaultBox { content: T; constructor(content: T) { this.content = content; } getContent(): T { return this.content; } } const box1 = new DefaultBox('default'); const box2 = new DefaultBox(42); console.log(box1.getContent()); console.log(box2.getContent());
Result
default 42
Understanding default types makes generic classes easier to use without always specifying types.
7
ExpertGeneric classes and inheritance
🤔Before reading on: do you think generic classes can be extended by other generic or non-generic classes? Commit to your answer.
Concept: Generic classes can be extended, and subclasses can specify or keep generic parameters for flexible inheritance.
class Container { content: T; constructor(content: T) { this.content = content; } } class DetailedContainer extends Container { detail: string; constructor(content: T, detail: string) { super(content); this.detail = detail; } getDetail(): string { return this.detail; } } const detailed = new DetailedContainer(100, 'important'); console.log(detailed.content); console.log(detailed.getDetail());
Result
100 important
Knowing how generics work with inheritance allows building complex, reusable class hierarchies.
Under the Hood
At runtime, TypeScript generics do not exist as types are erased during compilation to JavaScript. The generic parameters are only for compile-time checks and do not affect the generated code. The class behaves like a normal JavaScript class, but TypeScript ensures type safety during development.
Why designed this way?
TypeScript generics were designed to provide strong typing without changing JavaScript runtime behavior. This design keeps compatibility with JavaScript engines and libraries while giving developers powerful tools to catch errors early.
Generic Class Syntax

+---------------------+
| class Box<T>        |
| + content: T        |
| + constructor(T)    |
| + getContent(): T   |
+---------------------+
          |
          v
+---------------------+
| Instance with T=number |
| content = 123         |
+---------------------+

TypeScript checks types at compile time but outputs plain JavaScript.
Myth Busters - 4 Common Misconceptions
Quick: Do generic types exist at runtime in JavaScript? Commit to yes or no.
Common Belief:Generic types are present at runtime and affect how the JavaScript code runs.
Tap to reveal reality
Reality:Generics are erased during compilation; they only exist at compile time for type checking.
Why it matters:Thinking generics exist at runtime can lead to confusion about debugging and runtime errors.
Quick: Can you use any type as a generic parameter without restrictions? Commit to yes or no.
Common Belief:You can use any type as a generic parameter without limits.
Tap to reveal reality
Reality:You can restrict generic types using constraints like extends to ensure safety.
Why it matters:Ignoring constraints can cause runtime errors when methods or properties are missing.
Quick: Does specifying multiple generic parameters mean they are dependent on each other? Commit to yes or no.
Common Belief:Multiple generic parameters are always related or dependent on each other.
Tap to reveal reality
Reality:Generic parameters are independent unless explicitly connected by constraints or code logic.
Why it matters:Assuming dependency can cause incorrect assumptions about how data flows in the class.
Quick: Can you always omit generic parameters when creating instances? Commit to yes or no.
Common Belief:You can always omit generic parameters because TypeScript will infer them perfectly.
Tap to reveal reality
Reality:Type inference works in many cases but sometimes you must specify generic parameters explicitly.
Why it matters:Relying on inference blindly can cause confusing type errors or unexpected behavior.
Expert Zone
1
Generic classes can be combined with mapped types and conditional types for advanced type transformations.
2
Using generic constraints with keyof and extends allows creating very precise and safe APIs.
3
Default generic parameters can interact subtly with inheritance, affecting how subclasses infer types.
When NOT to use
Avoid generic classes when the type is always fixed or when runtime type information is needed; use regular classes or runtime type checks instead.
Production Patterns
Generic classes are widely used in data structures (like stacks, queues), API response wrappers, and utility classes where flexibility and type safety are critical.
Connections
Polymorphism in Object-Oriented Programming
Generic classes provide a form of compile-time polymorphism by allowing one class to work with many types.
Understanding generics deepens your grasp of how polymorphism can be achieved not only by inheritance but also by type parameters.
Templates in C++
TypeScript generics are conceptually similar to C++ templates, both allowing code reuse with different types.
Knowing about templates in C++ helps appreciate the power and limitations of generics in TypeScript.
Mathematical Functions with Parameters
Generic classes are like mathematical functions with parameters that produce different outputs based on input types.
Seeing generics as parameterized functions helps understand their flexibility and abstraction power.
Common Pitfalls
#1Using generic type parameters without constraints and then accessing properties that may not exist.
Wrong approach:class Box { content: T; getLength() { return this.content.length; // Error if T has no length } }
Correct approach:interface HasLength { length: number; } class Box { content: T; getLength() { return this.content.length; // Safe because of constraint } }
Root cause:Not restricting the generic type to types that have the needed properties causes type errors or runtime bugs.
#2Assuming generic types exist at runtime and trying to check them with typeof or instanceof.
Wrong approach:if (typeof T === 'string') { /* ... */ } // Invalid, T is erased
Correct approach:// Use runtime checks on values, not types if (typeof value === 'string') { /* ... */ }
Root cause:Confusing compile-time types with runtime values leads to invalid code and errors.
#3Forgetting to specify generic parameters when TypeScript cannot infer them.
Wrong approach:const box = new Box(); // Error: Generic type T not specified and cannot infer
Correct approach:const box = new Box(123); // Explicitly specify type
Root cause:Relying on inference when it’s not possible causes compiler errors.
Key Takeaways
Generic classes let you write flexible, reusable code by using type placeholders replaced when creating instances.
Generics exist only at compile time in TypeScript and do not affect the JavaScript runtime code.
You can restrict generic types with constraints to ensure safety and prevent errors.
Multiple generic parameters allow modeling complex data relationships in one class.
Understanding how generics work with inheritance and defaults unlocks advanced, maintainable designs.

Practice

(1/5)
1. What does the <T> mean in a TypeScript generic class declaration like class Box<T> {}?
easy
A. It declares a placeholder type that can be replaced with any type when creating an instance.
B. It defines a fixed type named T that cannot be changed.
C. It is a syntax error and should be removed.
D. It specifies that the class only works with numbers.

Solution

  1. Step 1: Understand generic type parameter

    The <T> after the class name declares a generic type parameter named T, which acts as a placeholder for any type.
  2. Step 2: Purpose of generic classes

    This allows the class to work flexibly with any type specified when creating an instance, making the code reusable and type-safe.
  3. Final Answer:

    It declares a placeholder type that can be replaced with any type when creating an instance. -> Option A
  4. Quick Check:

    Generic <T> = placeholder type [OK]
Hint: Generic <T> means flexible type placeholder [OK]
Common Mistakes:
  • Thinking <T> fixes the type permanently
  • Confusing generic syntax with inheritance
  • Assuming <T> is a variable or value
2. Which of the following is the correct syntax to declare a generic class named Container with a type parameter T?
easy
A. class Container[T] {}
B. class Container(T) {}
C. class Container {T} {}
D. class Container<T> {}

Solution

  1. Step 1: Recall generic class syntax

    In TypeScript, generic classes use angle brackets <> to declare type parameters after the class name.
  2. Step 2: Match correct syntax

    The correct syntax is class Container<T> {}. Other options use parentheses, curly braces, or square brackets incorrectly.
  3. Final Answer:

    class Container<T> {} -> Option D
  4. Quick Check:

    Generic class uses <T> syntax [OK]
Hint: Generic classes use angle brackets <T> after name [OK]
Common Mistakes:
  • Using parentheses instead of angle brackets
  • Placing type parameter inside class body
  • Using square brackets which are for arrays
3. What is the output of this TypeScript code?
class Box<T> {
  content: T;
  constructor(value: T) {
    this.content = value;
  }
  getContent(): T {
    return this.content;
  }
}

const box = new Box<string>('hello');
console.log(box.getContent());
medium
A. Box { content: 'hello' }
B. undefined
C. hello
D. TypeError at runtime

Solution

  1. Step 1: Understand class instantiation

    The class Box<T> is instantiated with T = string, so content is a string holding 'hello'.
  2. Step 2: Trace method call

    The method getContent() returns the stored content, which is 'hello'. The console.log prints this string.
  3. Final Answer:

    hello -> Option C
  4. Quick Check:

    Generic class returns stored value 'hello' [OK]
Hint: Generic class returns stored value of specified type [OK]
Common Mistakes:
  • Expecting object print instead of string
  • Confusing property with method output
  • Thinking generic causes runtime error
4. Identify the error in this generic class code:
class Pair<T, U> {
  first: T;
  second: U;
  constructor(first: T, second: T) {
    this.first = first;
    this.second = second;
  }
}
medium
A. Constructor parameters should be (first: T, second: U) to match property types.
B. Generic parameters should be declared as <T> only, not .
C. Properties first and second must have the same type T.
D. Constructor cannot have parameters in a generic class.

Solution

  1. Step 1: Compare constructor parameters with property types

    The class declares two generic types T and U, with properties first: T and second: U.
  2. Step 2: Identify mismatch in constructor

    The constructor incorrectly uses second: T instead of second: U, causing a type mismatch.
  3. Final Answer:

    Constructor parameters should be (first: T, second: U) to match property types. -> Option A
  4. Quick Check:

    Constructor params must match generic property types [OK]
Hint: Match constructor param types to generic properties [OK]
Common Mistakes:
  • Using same type for both parameters ignoring generics
  • Removing one generic parameter incorrectly
  • Thinking constructor can't have parameters in generics
5. You want to create a generic class Dictionary<K, V> that stores key-value pairs. Which implementation correctly uses generics to store and retrieve values by key?
class Dictionary<K, V> {
  private items: Map<K, V> = new Map();

  add(key: K, value: V): void {
    this.items.set(key, value);
  }

  get(key: K): V | undefined {
    return this.items.get(key);
  }
}
hard
A. Generic types cannot be used with Map in TypeScript.
B. This implementation correctly uses generics to store and retrieve values by key.
C. The add method should return the value added, not void.
D. The Map should be declared as Map<V, K> to match key-value order.

Solution

  1. Step 1: Analyze Map usage with generics

    The class uses Map<K, V> to store keys of type K and values of type V, which is correct.
  2. Step 2: Check methods for correct generic usage

    The add method sets a key-value pair, and get retrieves the value by key, both using the generic types properly.
  3. Final Answer:

    This implementation correctly uses generics to store and retrieve values by key. -> Option B
  4. Quick Check:

    Generic Map<K, V> with add/get methods = correct [OK]
Hint: Use Map with add/get methods for generic dictionary [OK]
Common Mistakes:
  • Swapping key and value types in Map declaration
  • Expecting add to return a value unnecessarily
  • Believing generics can't be used with built-in types
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard