Bird
Raised Fist0
Typescriptprogramming~15 mins

Generic arrow functions in Typescript - Deep Dive

Choose your learning style10 modes available
Overview - Generic arrow functions
What is it?
Generic arrow functions are special functions in TypeScript that can work with many types instead of just one. They use a placeholder for types, called a generic, so you can write one function that works with numbers, strings, or any other type. This makes your code flexible and reusable without repeating similar functions for each type. Arrow functions are a short way to write functions using the => symbol.
Why it matters
Without generic arrow functions, you would need to write many versions of the same function for different types, which wastes time and can cause mistakes. Generics let you write one function that adapts to different data types, making your code cleaner and easier to maintain. This helps when building big programs where many parts need similar operations but on different data types.
Where it fits
Before learning generic arrow functions, you should understand basic TypeScript types, functions, and arrow function syntax. After this, you can learn about advanced generics, constraints on generics, and how generics work with classes and interfaces.
Mental Model
Core Idea
A generic arrow function is like a recipe that uses a placeholder ingredient, so you can make many dishes by just changing that ingredient without rewriting the whole recipe.
Think of it like...
Imagine a cookie cutter that can shape dough into any shape you want by just swapping the mold. The cookie cutter is the generic arrow function, and the mold is the type you choose when you use it.
Generic Arrow Function Structure:

  functionName = <T>(input: T) => {
      // use input of type T
      return something;
  }

Where:
  - <T> is the generic type placeholder
  - input: T means input can be any type T
  - The function adapts to the type used when called
Build-Up - 7 Steps
1
FoundationBasic arrow function syntax
🤔
Concept: Learn how to write simple arrow functions in TypeScript.
An arrow function is a short way to write a function. For example: const greet = (name: string) => { return `Hello, ${name}!`; }; This function takes a string and returns a greeting.
Result
Calling greet('Alice') returns 'Hello, Alice!'.
Understanding arrow functions is essential because generic arrow functions build on this simple syntax.
2
FoundationIntroduction to generics
🤔
Concept: Understand what generics are and why they help with type flexibility.
Generics let you write functions that work with any type. For example: function identity(value: T): T { return value; } Here, T is a placeholder for any type. If you call identity(5), T is number; if you call identity('hi'), T is string.
Result
identity(5) returns 5, identity('hi') returns 'hi'.
Generics prevent repeating code for each type and keep type safety.
3
IntermediateCombining generics with arrow functions
🤔Before reading on: do you think you can write a generic arrow function exactly like a generic regular function? Commit to your answer.
Concept: Learn how to write generic arrow functions using the same generic syntax inside arrow functions.
You can write a generic arrow function by placing the generic type before the parameters: const identity = (value: T): T => { return value; }; This works like the generic function but uses arrow syntax.
Result
Calling identity('test') returns 'test' with type string.
Knowing that generics work the same way in arrow functions helps you write concise, flexible code.
4
IntermediateMultiple generic types in arrow functions
🤔Before reading on: can you guess how to add more than one generic type to an arrow function? Commit to your answer.
Concept: Learn to use multiple generic placeholders to handle more complex data relationships.
You can add multiple generics by separating them with commas: const pair = (first: T, second: U): [T, U] => { return [first, second]; }; This function returns a tuple of two different types.
Result
pair(1, 'a') returns [1, 'a'] with types [number, string].
Using multiple generics allows functions to handle different types together while keeping type safety.
5
IntermediateGeneric constraints in arrow functions
🤔Before reading on: do you think generics can be limited to certain types? Commit to your answer.
Concept: Learn how to restrict generic types to those that meet certain conditions using constraints.
You can limit generics with extends keyword: interface Lengthwise { length: number; } const logLength = (item: T): T => { console.log(item.length); return item; }; This function only accepts types with a length property.
Result
Calling logLength('hello') logs 5 and returns 'hello'. Calling logLength(10) causes a type error.
Constraints keep generics safe by ensuring the type has needed properties.
6
AdvancedInferring generic types in arrow functions
🤔Before reading on: do you think TypeScript always needs you to specify generic types explicitly? Commit to your answer.
Concept: Understand how TypeScript can guess generic types from function arguments to reduce extra typing.
When you call a generic arrow function, TypeScript often infers the type: const identity = (value: T): T => value; const result = identity(42); // T inferred as number You don't need to write identity(42) unless you want to be explicit.
Result
result has type number and value 42.
Type inference makes generics easier to use and keeps code clean.
7
ExpertGeneric arrow functions with default types
🤔Before reading on: can generic types have default values in arrow functions? Commit to your answer.
Concept: Learn how to provide default types for generics to simplify function calls when a common type is used.
You can assign default types like this: const makeArray = (item: T): T[] => { return [item]; }; If you call makeArray('hello'), T is string by default. You can override it by makeArray(5).
Result
makeArray('hi') returns ['hi'] with type string[]. makeArray(5) returns [5] with type number[].
Default generic types reduce verbosity and improve developer experience in common cases.
Under the Hood
At runtime, TypeScript generics do not exist because they are erased during compilation to JavaScript. The generic types are only used by the TypeScript compiler to check types and ensure safety before running the code. Arrow functions are compiled into JavaScript functions with a concise syntax. The generic placeholders guide the compiler to enforce correct types but do not affect the generated JavaScript code.
Why designed this way?
TypeScript was designed to add type safety without changing JavaScript's runtime behavior. Generics provide flexible typing without runtime overhead. Arrow functions were introduced in JavaScript for shorter syntax and lexical this binding. Combining generics with arrow functions keeps code concise and type-safe, matching modern JavaScript style.
TypeScript Source Code
  └─> Generic Arrow Function with <T>
        └─> Compiler checks types using T
              └─> Erases <T> and outputs plain JavaScript arrow function
                    └─> Runs in JavaScript environment without types
Myth Busters - 4 Common Misconceptions
Quick: Do generic types exist at runtime in JavaScript? Commit to yes or no.
Common Belief:Generics are real types that exist when the program runs.
Tap to reveal reality
Reality:Generics are only used during TypeScript compilation and do not exist in the final JavaScript code.
Why it matters:Thinking generics exist at runtime can lead to confusion about debugging and runtime errors.
Quick: Can you use arrow function shorthand syntax with generics without parentheses? Commit to yes or no.
Common Belief:You can write a generic arrow function like const f = x => x; without parentheses around parameters.
Tap to reveal reality
Reality:You must use parentheses around parameters when using generics, like const f = (x) => x; otherwise, it's a syntax error.
Why it matters:Missing parentheses causes syntax errors that beginners find confusing.
Quick: Does TypeScript always require you to specify generic types explicitly? Commit to yes or no.
Common Belief:You must always write the generic type when calling a generic arrow function.
Tap to reveal reality
Reality:TypeScript often infers generic types from arguments, so explicit types are not always needed.
Why it matters:Not knowing inference leads to verbose and less readable code.
Quick: Can you use any type as a generic without restrictions? Commit to yes or no.
Common Belief:Generics accept any type without limits, so you don't need to restrict them.
Tap to reveal reality
Reality:Sometimes you need to restrict generics with constraints to ensure the type has required properties.
Why it matters:Ignoring constraints can cause runtime errors when expected properties are missing.
Expert Zone
1
Generic arrow functions can be combined with conditional types to create highly flexible and type-safe utilities.
2
Default generic types improve usability but can sometimes hide type errors if overused without care.
3
Type inference for generics works best with simple types; complex expressions may require explicit annotations.
When NOT to use
Avoid generic arrow functions when the function logic depends heavily on specific types or when runtime type information is needed. In such cases, use function overloads or explicit type checks instead.
Production Patterns
In production, generic arrow functions are widely used in utility libraries, React hooks, and data transformation functions to write reusable and type-safe code. They help reduce duplication and improve maintainability.
Connections
Polymorphism in Object-Oriented Programming
Both generics and polymorphism allow code to work with different types flexibly.
Understanding generics deepens your grasp of polymorphism by showing how type flexibility can be enforced at compile time.
Templates in C++
Generics in TypeScript are similar to templates in C++, both enable writing code that works with any type.
Knowing how templates work in C++ helps appreciate the power and limitations of TypeScript generics.
Mathematical Functions with Variables
Generic functions are like mathematical functions with variables representing any number, allowing general formulas.
Seeing generics as placeholders for any value connects programming to abstract math thinking.
Common Pitfalls
#1Forgetting parentheses around parameters in generic arrow functions.
Wrong approach:const identity = x => x;
Correct approach:const identity = (x) => x;
Root cause:Syntax requires parentheses when using generics with arrow functions, but beginners often omit them.
#2Assuming generic types exist at runtime and trying to check them.
Wrong approach:const isString = (value: T) => typeof T === 'string';
Correct approach:const isString = (value: unknown): value is string => typeof value === 'string';
Root cause:Generics are erased at runtime, so you cannot check generic types with typeof.
#3Not using constraints when the function needs specific properties.
Wrong approach:const logLength = (item: T) => console.log(item.length);
Correct approach:const logLength = (item: T) => console.log(item.length);
Root cause:Without constraints, TypeScript cannot guarantee the property exists, causing errors.
Key Takeaways
Generic arrow functions combine flexible typing with concise syntax to write reusable, type-safe code.
Generics are compile-time tools that do not exist at runtime, so they cannot be checked with JavaScript operators.
Using constraints on generics ensures functions only accept types with required properties, preventing errors.
TypeScript often infers generic types, reducing the need for explicit type annotations and keeping code clean.
Default generic types simplify function calls when a common type is expected but can be overridden when needed.

Practice

(1/5)
1.

What does the <T> represent in a generic arrow function in TypeScript?

easy
A. A variable name for a function parameter
B. A placeholder for a type that will be specified later
C. A keyword to declare a constant
D. A special operator for comparison

Solution

  1. Step 1: Understand generic type parameters

    The <T> syntax declares a generic type parameter, which acts as a placeholder for any type.
  2. Step 2: Recognize its purpose in functions

    This allows the function to work with different types while keeping type safety.
  3. Final Answer:

    A placeholder for a type that will be specified later -> Option B
  4. Quick Check:

    Generic type parameter = placeholder type [OK]
Hint: Think of <T> as a flexible type placeholder [OK]
Common Mistakes:
  • Confusing <T> with a variable name
  • Thinking <T> is a keyword like const or let
  • Assuming <T> is an operator
2.

Which of the following is the correct syntax for a generic arrow function that returns the same type it receives?

?
easy
A. const identity = <T> = (arg: T): T => arg;
B. const identity = <T>: (arg: T) => T => arg;
C. const identity = <T>(arg: T): T => arg;
D. const identity = <T> (arg: T) => { return arg; };

Solution

  1. Step 1: Check generic arrow function syntax

    The generic type parameter <T> must come immediately after the function name without an equals sign.
  2. Step 2: Verify arrow function structure

    The function takes an argument of type T and returns the same type T. const identity = <T>(arg: T): T => arg; matches this syntax correctly.
  3. Final Answer:

    const identity = <T>(arg: T): T => arg; -> Option C
  4. Quick Check:

    Correct generic arrow function syntax = const identity = <T>(arg: T): T => arg; [OK]
Hint: Generic syntax: const fn = <T>(arg: T): T => ... [OK]
Common Mistakes:
  • Adding an equals sign after <T>
  • Misplacing parentheses around <T>
  • Using incorrect arrow function syntax
3.

What will be the output of this TypeScript code?

const wrapInArray = <T>(value: T): T[] => [value];

console.log(wrapInArray(5));
console.log(wrapInArray('hello'));
medium
A. [5] ['hello']
B. 5 hello
C. [5, 'hello']
D. Error: Type mismatch

Solution

  1. Step 1: Understand the generic function behavior

    The function wrapInArray takes a value of any type T and returns an array containing that value.
  2. Step 2: Analyze the console.log outputs

    Calling wrapInArray(5) returns [5], and wrapInArray('hello') returns ['hello'].
  3. Final Answer:

    [5] ['hello'] -> Option A
  4. Quick Check:

    Generic function returns array with input value [OK]
Hint: Generic function wraps input in array, output matches input type [OK]
Common Mistakes:
  • Expecting output without array brackets
  • Thinking it returns a tuple
  • Confusing types causing errors
4.

Identify the error in this generic arrow function and choose the corrected version:

const getFirst = <T> = (arr: T[]): T => {
  return arr[0];
};
medium
A. const getFirst = <T> (arr: T[]): T => { return arr[0]; };
B. const getFirst = (arr: T[]): T => arr[0];
C. const getFirst = <T>: (arr: T[]) => T => arr[0];
D. const getFirst = <T>(arr: T[]): T => arr[0];

Solution

  1. Step 1: Identify incorrect syntax in original code

    The original code incorrectly uses an equals sign after <T>, which is not valid syntax for generic arrow functions.
  2. Step 2: Choose the correct syntax

    const getFirst = <T>(arr: T[]): T => arr[0]; correctly places <T> immediately after the function name without an equals sign and uses concise arrow function syntax.
  3. Final Answer:

    const getFirst = <T>(arr: T[]): T => arr[0]; -> Option D
  4. Quick Check:

    Generic arrow function syntax = const getFirst = <T>(arr: T[]): T => arr[0]; [OK]
Hint: No equals sign after <T> in generic arrow functions [OK]
Common Mistakes:
  • Adding equals sign after <T>
  • Omitting generic parameter <T>
  • Incorrect arrow function syntax
5.

Given this generic arrow function, what is the output of mergeObjects({a: 1}, {b: 2})?

const mergeObjects = <T, U>(obj1: T, obj2: U): T & U => ({ ...obj1, ...obj2 });

console.log(mergeObjects({a: 1}, {b: 2}));
hard
A. { a: 1, b: 2 }
B. { a: 1 }
C. { b: 2 }
D. TypeError at runtime

Solution

  1. Step 1: Understand the generic parameters and return type

    The function takes two objects of types T and U and returns their intersection type T & U, meaning it combines properties from both.
  2. Step 2: Analyze the spread operator usage

    The spread operator merges properties from both objects into a new object containing all keys and values.
  3. Step 3: Predict the output of the console.log

    Calling mergeObjects({a: 1}, {b: 2}) returns { a: 1, b: 2 }.
  4. Final Answer:

    { a: 1, b: 2 } -> Option A
  5. Quick Check:

    Spread merge of two objects = combined object [OK]
Hint: Spread operator merges objects, output has all keys [OK]
Common Mistakes:
  • Expecting only first or second object properties
  • Confusing intersection type with union
  • Thinking it causes runtime error
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