easyExtra#92

TypeScript generics — identity function

Prompt

Write a generic identity function that returns the same type it receives. Use it with a string and a number relying on inference, and once with an explicit type argument.

Solution

function identity<T>(arg: T): T {
  return arg
}

// Inference: T is captured from the argument — no annotation needed
const str = identity('hello') // T = string
const num = identity(42)      // T = number

// Explicit type argument — only when inference has nothing to work with
const tags = identity<string[]>([])
Mentor's take

Generics exist to preserve the relationship between input and output types. identity is deliberately trivial — the interviewer is checking whether you understand that <T> declares a type parameter captured fresh at each call site: identity('hello') instantiates T = string, identity(42) instantiates T = number, and no annotation is needed because inference reads the argument.

The senior contrast is with any: function identity(arg: any): any also compiles, but it erases the type — the caller gets any back and every downstream property access is unchecked. The generic keeps the pipe type-safe end to end without writing one overload per type.

Trade-offs worth saying out loud: pass an explicit type argument (identity<string[]>([])) only when inference has nothing to anchor on — an empty array, or a literal you don't want widened. And generics are compile-time only: they erase at runtime, so there is no typeof T, and any runtime branching still needs a real value to inspect.

Red flag: answering with any or a stack of overloads. Both "work"; both tell the interviewer you don't know why the feature exists — any opts out of the type system exactly where the question asked you to use it.

Say it: "A generic is a type variable captured at the call site — it preserves the input/output type relationship that any would erase, with inference doing the annotation work for me."