一键导入
function-type-expressions
Use when writing multiple functions with same signature. Use when implementing callbacks. Use when matching existing function types.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when writing multiple functions with same signature. Use when implementing callbacks. Use when matching existing function types.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when defining global types. Use when augmenting window. Use when typing environment variables. Use when working with build-time constants. Use when configuring type definitions.
Use when migrating JavaScript to TypeScript. Use when gradually adopting TypeScript. Use when working with mixed codebases. Use when converting large projects. Use when teams are learning TypeScript.
Use when writing asynchronous code. Use when tempted to use callbacks. Use when composing multiple async operations.
Use when creating types from example data. Use when types don't match all cases. Use when API responses vary.
Use when writing type annotations on variables. Use when TypeScript can infer the type. Use when code feels cluttered with types.
Use when defining array-like types. Use when tempted to use number as index type. Use when understanding array keys.
| name | function-type-expressions |
| description | Use when writing multiple functions with same signature. Use when implementing callbacks. Use when matching existing function types. |
Type entire functions at once instead of individual parameters.
When using function expressions (not statements), you can apply a type to the entire function. This reduces repetition, improves type safety, and makes code more readable.
When functions share a signature, define the type ONCE and apply it to EACH function.
Remember:
typeof fn to match existing function signatures// Repetitive - same signature 4 times
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; // Types inferred
const sub: BinaryFn = (a, b) => a - b;
const mul: BinaryFn = (a, b) => a * b;
const div: BinaryFn = (a, b) => a / b;
Benefits:
// Match fetch's signature exactly
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;
};
TypeScript infers:
input: RequestInfo | URLinit?: RequestInitPromise<Response>// Match parameters but change return type
async function fetchNumber(
...args: Parameters<typeof fetch>
): Promise<number> {
const response = await checkedFetch(...args);
return Number(await response.text());
}
// Statement - must annotate each parameter
function rollDice1(sides: number): number { /* ... */ }
// Expression - can apply type to entire function
type DiceRollFn = (sides: number) => number;
const rollDice2: DiceRollFn = (sides) => { /* ... */ };
type EventHandler = (event: Event) => void;
type AsyncCallback<T> = () => Promise<T>;
type Comparator<T> = (a: T, b: T) => number;
const handleClick: EventHandler = (e) => {
console.log(e.target); // e is typed as Event
};
type Mapper<T, U> = (item: T, index: number) => U;
const double: Mapper<number, number> = (n) => n * 2;
const stringify: Mapper<number, string> = (n) => String(n);
// Function type as interface
interface StringTransform {
(input: string): string;
}
const toUpper: StringTransform = s => s.toUpperCase();
Function types catch return type errors:
const checkedFetch: typeof fetch = async (input, init) => {
const response = await fetch(input, init);
if (!response.ok) {
return new Error('Failed'); // Error!
// Type 'Error' is not assignable to type 'Response'
}
return response;
};
Without the function type, this would only error at call sites.
Libraries often provide callback types:
// React provides these
import { MouseEventHandler, ChangeEventHandler } from 'react';
const handleClick: MouseEventHandler<HTMLButtonElement> = (e) => {
console.log(e.currentTarget.disabled); // Fully typed
};
const handleChange: ChangeEventHandler<HTMLInputElement> = (e) => {
console.log(e.target.value); // Fully typed
};
Don't over-engineer for single functions:
// Overkill for a single standalone function
type GreetFn = (name: string) => string;
const greet: GreetFn = (name) => `Hello, ${name}`;
// Just use a normal function statement
function greet(name: string): string {
return `Hello, ${name}`;
}
Pressure: "I prefer seeing types inline with parameters"
Response: With shared signatures, centralizing the type removes noise.
Action: Use function types when 2+ functions share a signature.
Pressure: "I can't find the callback type in the library"
Response: Use typeof existingFunction or Parameters<typeof fn>.
Action: Match existing signatures with typeof.
| Excuse | Reality |
|---|---|
| "Types on parameters are clearer" | Not when repeated 4 times |
| "Function statements are simpler" | Function expressions with types are just as clear |
"I'll just use any" | Loses all type safety benefits |
// Define function type
type Transform<T> = (value: T) => T;
// Apply to function expression
const double: Transform<number> = v => v * 2;
// Match existing function
const myFetch: typeof fetch = async (input, init) => { ... };
// Match parameters, change return
function wrapper(...args: Parameters<typeof original>): NewReturn { ... }
Apply types to entire function expressions when you have shared signatures.
This reduces repetition, centralizes type definitions, and catches return type errors at the source. Use typeof to match existing function signatures exactly.
Based on "Effective TypeScript" by Dan Vanderkam, Item 12: Apply Types to Entire Function Expressions When Possible.