function process(callback: (value: number) => void) {
callback(42);
}
process((n) => console.log(n));
Topics
26
Classes: Access Modifiers, Abstract Classes & Implements
Conditional Types
Declaration Files
Decorators
Discriminated Unions & Exhaustiveness Checking
Enums
Function Types, Overloads & Optional/Default Parameters
Generics
Index Signatures & Record Types
Mapped Types
Migrating JavaScript to TypeScript
Modules
Namespaces & Declaration Merging
Never, Unknown & Void Types
Nullability: strictNullChecks, Optional Chaining & Nullish Coalescing
Primitive Types, Arrays & Tuples
Readonly, const Assertions & Immutability
Structural Typing & Duck Typing
Template Literal Types
tsconfig & Compiler Options
Type Assertions & Type Casting
Type Inference & Contextual Typing
Type Narrowing & Guards
Types & Interfaces
Union & Intersection Types
Utility Types
Function Types, Overloads & Optional/Default Parameters
10 questions found
Use arrow-style syntax `(param: Type) => ReturnType` to describe a function's shape, specifying each parameter's type and the return type.
Real-world example
Typing a callback parameter passed to an array method wrapper or an event handler registration function.
Generics
Add a '?' after the parameter name; TypeScript automatically adds 'undefined' to its type, and optional parameters must come after all required parameters in the parameter list.
function greet(name: string, title?: string) {
return title ? `${title} ${name}` : name;
}
greet('Sam'); // 'Sam'
greet('Sam', 'Dr.'); // 'Dr. Sam'
Real-world example
Making a configuration parameter optional so callers can omit it and rely on default in-function behavior.
Nullability: strictNullChecks
Optional Chaining & Nullish Coalescing
How do you give a function parameter a default value, and how does TypeScript infer its type?
BeginnerAssign a default value directly in the parameter list using '='; TypeScript infers the parameter's type from the default value's type unless you also add an explicit annotation, and the parameter becomes optional to callers.
function greet(name: string, greeting = 'Hello') {
return `${greeting}, ${name}`;
}
greet('Sam'); // 'Hello, Sam'
greet('Sam', 'Hi'); // 'Hi, Sam'
Real-world example
Providing a sensible default page size or sort order for a paginated query function.
Type Inference & Contextual Typing
What are function overloads, and how do they let a single function name handle multiple different call signatures?
IntermediateYou declare multiple overload signatures (no implementation) followed by one general implementation signature that's compatible with all of them; TypeScript uses the overload signatures for type-checking calls, picking the first matching one, while the implementation signature is only used internally and isn't visible to callers.
function makeDate(timestamp: number): Date;
function makeDate(year: number, month: number, day: number): Date;
function makeDate(yearOrTimestamp: number, month?: number, day?: number): Date {
return month !== undefined
? new Date(yearOrTimestamp, month, day!)
: new Date(yearOrTimestamp);
}
makeDate(2026); // uses first overload
makeDate(2026, 7, 8); // uses second overload
Real-world example
Supporting both a single-timestamp and a year/month/day style call for a date-construction utility, each with precise argument-count checking.
Union & Intersection Types
How do rest parameters work with type annotations, and what type must the annotation be?
IntermediateA rest parameter (prefixed with '...') collects any remaining arguments into an array, so its type annotation must be an array type (or tuple type for fixed-shape variadic arguments), matching how rest parameters behave in plain JavaScript.
function sum(...nums: number[]): number {
return nums.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3); // 6
Real-world example
Typing a logging function that accepts a variable number of arguments of the same type.
Primitive Types
Arrays & Tuples
How does TypeScript check compatibility between two function types, particularly regarding parameter counts?
IntermediateA function type A is assignable to function type B if A's parameters are compatible with B's (contravariantly, roughly) AND A doesn't require MORE parameters than B provides — meaning a function taking fewer parameters can safely stand in for one expecting more, since extra arguments are simply ignored, but not the reverse.
type Handler = (event: Event, index: number) => void;
const handler: Handler = (event) => console.log(event); // OK: fewer params allowed
// const bad: Handler = (event, index, extra) => {}; // Error: too many required params
Real-world example
Passing a simple callback like `(item) => ...` where an array method expects `(item, index, array) => ...`.
Structural Typing & Duck Typing
How do you write a generic function type with overloads that behave differently based on a literal argument value?
AdvancedCombine overload signatures with specific literal parameter types for each variant, letting the return type or accepted shape change based on that literal — commonly used for APIs like document.createElement, where the tag name literal determines the specific returned element type.
function createElement(tag: 'a'): HTMLAnchorElement;
function createElement(tag: 'img'): HTMLImageElement;
function createElement(tag: string): HTMLElement {
return document.createElement(tag);
}
const link = createElement('a'); // typed as HTMLAnchorElement
Real-world example
Precisely typing a factory function whose return shape depends on a specific string literal argument, like DOM element creation.
Conditional Types
Why must the overload signatures be listed from MOST specific to LEAST specific, and what bug occurs if this order is reversed?
AdvancedTypeScript resolves overloads by picking the FIRST signature (top to bottom) that matches the call — if a broader, less specific overload is listed before a more specific one, it will always match first, silently shadowing the more specific overload and giving callers a less precise type than intended.
// WRONG ORDER: general overload shadows the specific one
function process(value: unknown): string;
function process(value: number): number; // unreachable! unknown already matched
function process(value: any): any { /* ... */ }
process(42); // incorrectly resolves to the 'unknown' overload, returns string type
Real-world example
Debugging why a specific overload's more precise return type never gets applied, tracing it to overload ordering.
Never
Unknown & Void Types
How do 'this' parameter annotations work in a function type, and what problem do they solve?
AdvancedAn explicit `this: SomeType` as the FIRST parameter (removed from the actual call signature) tells TypeScript what type 'this' must be when the function is called, letting the compiler catch incorrect method extraction or binding — like passing an object method as a bare callback where 'this' would be lost.
interface Button {
label: string;
onClick(this: Button, event: Event): void;
}
const button: Button = {
label: 'Save',
onClick(this: Button, event) {
console.log(this.label); // 'this' is correctly typed as Button here
}
};
Real-world example
Catching a bug where a class method is passed as a raw callback (losing its 'this' binding) before it causes a runtime error.
this & Binding
How would you type a higher-order function that accepts a function and returns a new function with an additional, injected parameter removed from its signature?
AdvancedUse generics with the built-in Parameters<T> and ReturnType<T> utility types (or simple generic inference) to derive the wrapped function's exact parameter and return types automatically, producing full type safety without manually re-declaring the shape.
function withLogging<Args extends unknown[], R>(
fn: (...args: Args) => R
): (...args: Args) => R {
return (...args: Args): R => {
console.log('calling with', args);
return fn(...args);
};
}
const add = (a: number, b: number) => a + b;
const loggedAdd = withLogging(add); // inferred as (a: number, b: number) => number
Real-world example
Writing a generic, fully type-safe decorator-like wrapper (logging, timing, memoization) that preserves the original function's exact signature.
Generics