Skip to content

Latest commit

 

History

History
161 lines (122 loc) · 7.42 KB

type-entire-functions.md

File metadata and controls

161 lines (122 loc) · 7.42 KB

Item 12: Apply Types to Entire Function Expressions When Possible

Things to Remember

  • Consider applying type annotations to entire function expressions, rather than to their parameters and return type.
  • If you're writing the same type signature repeatedly, factor out a function type or look for an existing one.
  • If you're a library author, provide types for common callbacks.
  • Use typeof fn to match the signature of another function, or Parameters and a rest parameter if you need to change the return type.

Code Samples

function rollDice1(sides: number): number { /* ... */ }  // Statement
const rollDice2 = function(sides: number): number { /* ... */ };  // Expression
const rollDice3 = (sides: number): number => { /* ... */ };  // Also expression

💻 playground


type DiceRollFn = (sides: number) => number;
const rollDice: DiceRollFn = sides => { /* ... */ };

💻 playground


function add(a: number, b: number) { return a + b; }
function sub(a: number, b: number) { return a - b; }
function mul(a: number, b: number) { return a * b; }
function div(a: number, b: number) { return a / b; }

💻 playground


type BinaryFn = (a: number, b: number) => number;
const add: BinaryFn = (a, b) => a + b;
const sub: BinaryFn = (a, b) => a - b;
const mul: BinaryFn = (a, b) => a * b;
const div: BinaryFn = (a, b) => a / b;

💻 playground


const response = fetch('/quote?by=Mark+Twain');
//    ^? const response: Promise<Response>

💻 playground


async function getQuote() {
  const response = await fetch('/quote?by=Mark+Twain');
  const quote = await response.json();
  return quote;
}
// {
//   "quote": "If you tell the truth, you don't have to remember anything.",
//   "source": "notebook",
//   "date": "1894"
// }

💻 playground


declare function fetch(
  input: RequestInfo, init?: RequestInit,
): Promise<Response>;

💻 playground


async function checkedFetch(input: RequestInfo, init?: RequestInit) {
  const response = await fetch(input, init);
  if (!response.ok) {
    // An exception becomes a rejected Promise in an async function.
    throw new Error(`Request failed: ${response.status}`);
  }
  return response;
}

💻 playground


const checkedFetch: typeof fetch = async (input, init) => {
  const response = await fetch(input, init);
  if (!response.ok) {
    throw new Error(`Request failed: ${response.status}`);
  }
  return response;
}

💻 playground


const checkedFetch: typeof fetch = async (input, init) => {
  //  ~~~~~~~~~~~~
  //  'Promise<Response | HTTPError>' is not assignable to 'Promise<Response>'
  //    Type 'Response | HTTPError' is not assignable to type 'Response'
  const response = await fetch(input, init);
  if (!response.ok) {
    return new Error('Request failed: ' + response.status);
  }
  return response;
}

💻 playground


async function fetchANumber(
    ...args: Parameters<typeof fetch>
): Promise<number> {
  const response = await checkedFetch(...args);
  const num = Number(await response.text());
  if (isNaN(num)) {
    throw new Error(`Response was not a number.`);
  }
  return num;
}

💻 playground


fetchANumber
// ^? function fetchANumber(
//      input: RequestInfo | URL, init?: RequestInit | undefined
//    ): Promise<number>

💻 playground