Generic factory pattern in Typescript - Time & Space Complexity
We want to see how the time cost changes when using a generic factory pattern in TypeScript.
How does creating objects with this pattern scale as we ask for more objects?
Analyze the time complexity of the following code snippet.
interface Product {
name: string;
}
function createProduct(ctor: new () => T): T {
return new ctor();
}
class Toy implements Product {
name = 'Toy';
}
const toy = createProduct(Toy);
This code defines a generic factory function that creates an object of any class that implements Product.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Creating a single object instance using the constructor.
- How many times: Exactly once per call to the factory function.
Each time we call the factory, one new object is created. If we call it multiple times, the work grows directly with the number of calls.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 object creations |
| 100 | 100 object creations |
| 1000 | 1000 object creations |
Pattern observation: The time grows linearly as we create more objects.
Time Complexity: O(n)
This means the time to create n objects grows directly in proportion to n.
[X] Wrong: "Creating an object with the factory is instant and does not depend on how many times we call it."
[OK] Correct: Each call creates a new object, so more calls mean more work, not zero time.
Understanding how object creation scales helps you explain performance in real apps and shows you know how patterns affect speed.
"What if the factory function created multiple objects inside a loop? How would the time complexity change?"
Practice
What is the main purpose of the Generic factory pattern in TypeScript?
Solution
Step 1: Understand the pattern's goal
The generic factory pattern is designed to create objects without needing to know their exact class ahead of time.Step 2: Compare options with the pattern's purpose
To create objects without specifying their exact class. correctly states this purpose. Other options describe unrelated features.Final Answer:
To create objects without specifying their exact class. -> Option BQuick Check:
Generic factory pattern = create objects flexibly [OK]
- Confusing with async handling
- Thinking it enforces variable typing
- Assuming it optimizes runtime speed
Which of the following is the correct syntax to declare a generic factory function in TypeScript?
function create<T>(): T { /* ... */ }Solution
Step 1: Analyze generic function syntax
The function declares a generic typeTand returns an object of typeT.Step 2: Check return statements for correctness
function create<T>(): T { return {} as T; } uses a type assertion{} as Twhich is valid to create a generic placeholder object. function create<T>(): T { return new T(); } tries to usenew T()which is invalid becauseTis a type parameter, not a constructor. function create<T>(): T { return T(); } callsT()like a function which is invalid. function create<T>(): T { return new Object(); } returns a generic object but not typed asT.Final Answer:
function create<T>(): T { return {} as T; } -> Option DQuick Check:
Generic factory syntax = use type assertion [OK]
- Trying to instantiate generic type with new
- Calling generic type as a function
- Returning untyped objects without assertion
What will be the output of this TypeScript code using a generic factory pattern?
interface Animal { speak(): string; }
class Dog implements Animal { speak() { return "Woof"; } }
function createAnimal<T extends Animal>(ctor: new () => T): T {
return new ctor();
}
const dog = createAnimal(Dog);
console.log(dog.speak());Solution
Step 1: Understand the factory function behavior
The functioncreateAnimaltakes a constructorctorand returns a new instance of typeTwhich extendsAnimal.Step 2: Trace the code execution
We passDogclass tocreateAnimal, so it returns a newDoginstance. Callingdog.speak()returns "Woof".Final Answer:
"Woof" -> Option AQuick Check:
Generic factory creates Dog, speak() = "Woof" [OK]
- Assuming generic type can't be instantiated
- Confusing type constraints with runtime errors
- Expecting undefined instead of method return
Identify the error in this generic factory function and select the fix.
function createInstance<T>(): T {
return new T();
}Solution
Step 1: Identify why
TypeScript does not allownew T()causes errornew T()becauseTis a type parameter, not a constructor function.Step 2: Apply correct fix using constructor parameter
Passing a constructor functionctor: new () => Tallows callingnew ctor()to create an instance ofT.Final Answer:
Add a constructor parameter:ctor: new () => Tand returnnew ctor(). -> Option AQuick Check:
Generic factory needs constructor parameter [OK]
- Trying to instantiate generic type directly
- Removing new keyword incorrectly
- Changing return type to any loses type safety
You want to create a generic factory that can produce different shapes with a draw() method. Which approach correctly uses the generic factory pattern to support adding new shapes easily?
interface Shape { draw(): void; }
class Circle implements Shape { draw() { console.log("Circle"); } }
class Square implements Shape { draw() { console.log("Square"); } }
// What is the best factory implementation?Solution
Step 1: Understand the requirement for flexibility
The factory should create any shape implementingShapewithout hardcoding types.Step 2: Evaluate each option
function createShape(ctor: new () => T): T { return new ctor(); } uses a generic constructor parameter allowing easy addition of new shapes. function createShape(): Shape { return new Circle(); } always returns Circle, no flexibility. function createShape(type: string): Shape { if(type === 'circle') return new Circle(); else return new Square(); } uses string checks, less type-safe and harder to extend. function createShape<T>(): T { return {} as T; } returns an empty object cast toT, which is unsafe.Final Answer:
function createShape<T extends Shape>(ctor: new () => T): T { return new ctor(); } -> Option CQuick Check:
Generic factory with constructor param = flexible shape creation [OK]
- Hardcoding return types limits extensibility
- Using string type checks reduces type safety
- Casting empty objects loses real behavior
Ready to prove it?
Pass the test and this pattern moves unknown
