Item 12: Apply Types to Entire Function Expressions When Possible
May 10, 2024 ยท View on GitHub
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 fnto match the signature of another function, orParametersand 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
type DiceRollFn = (sides: number) => number;
const rollDice: DiceRollFn = sides => { /* ... */ };
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; }
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;
const response = fetch('/quote?by=Mark+Twain');
// ^? const response: Promise<Response>
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"
// }
declare function fetch(
input: RequestInfo, init?: RequestInit,
): Promise<Response>;
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;
}
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;
}
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;
}
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;
}
fetchANumber
// ^? function fetchANumber(
// input: RequestInfo | URL, init?: RequestInit | undefined
// ): Promise<number>