Skip to main content

Conditional Return Types in TypeScript

  • Using Overloads in TypeScript to Narrow a Function’s Return Type

  • What are function overloads in TypeScript?

  • How to narrow a TS function’s return type based on its parameters’ types?

  • How to narrow a TypeScript function’s return type based on its parameter types?

  • Your function’s return type is a union of multiple possibilities, but depending on the parameters passed in, you want to narrow those possibilities to one so consumers know exactly what type their receiving

  • If TS isn’t figuring out those conditional types on its own, you need to overload your function definition for each combination of parameter types + return types

  • Above your implementation, repeat the signature with as many specific combos of param/return types as there are

    • add code examples
    • StackOverflow example:
function makeBinsFromArray<T>(
  value: T[],
  binSize: number,
  fillLast: true
): (T | undefined)[][]
 
function makeBinsFromArray<T>(
  value: T[],
  binSize: number,
  fillLast?: false
): T[][]
 
function makeBinsFromArray<T>(
  value: T[],
  binSize: number,
  fillLast?: boolean
): (T | (T | undefined))[][] {
  /// implementation
}
 
const resultA = makeBinsFromArray([1, 2, 3], 2, true);
// (T | undefined)[][]
 
const resultB = makeBinsFromArray([1, 2, 3], 2);
// T[][];
  • base more on useQueryParams.ts example

    • one param in an options object is simpler than 3 params
  • Those overload signatures should have no implementation (no body); just a signature

  • Your goal is to tell TS exactly what the function’s return type should be in each param type scenario

  • Then, after those specific overloads comes your original function with its broader param and return types encompassing all the possibilities + the implementation of the function body

  • Rules:

    • Same number of arguments
    • You can define as many overload declarations as you like, but only one overload can implement the function
    • The function signature of the implementation function must be a union of all the other function declaration types
    • You must define all of the function declarations with the function keyword (rather than let or const); if you don’t, you’ll wonder why TS is giving you a duplicate identifier error while you’re using a supported TS feature

    Note: Functions with same name and different number of arguments are not understood by TS as overloaded functions.

How to make ESLint happy

  • use actual error term and link to the docs
  • show the ignore comment options
    • /* eslint-disable no-redeclare */

Further reading

Inbox