A function type `A` is assignable to another function type `B` if `A`'s parameters are compatible with `B`'s (contravariantly, loosely enforced for methods) and `A`'s return type is assignable to `B`'s return type (covariantly).
ts
type Handler = (event: { type: string; amount: number }) => void;
// A function that accepts fewer/broader-typed properties can be assigned,
// since it can handle anything Handler's caller passes it:
const logAmount: (event: { amount: number }) => void = (e) => console.log(e.amount);
const h: Handler = logAmount; // OK: logAmount only needs 'amount', which Handler always provides
function process(items: number[], cb: (n: number) => void) {
items.forEach(cb);
}
process([1, 2, 3], (n: number) => console.log(n));Return types must be compatible in the same direction as the assignment (a function returning a more specific type can substitute for one expecting a more general type), while `strictFunctionTypes` tightens parameter checking for standalone function types (not methods) to catch genuinely unsound assignments.