Master TypeScript Function Overloads with the overload-func Library
This article explains how to use the overload-func library to separate implementation from overload signatures in TypeScript, providing runtime matching, full type checking, and flexible configuration while keeping the codebase clean and maintainable.
Preface
When building generic libraries that need multiple overload signatures, TypeScript's native overloads can become messy. This article introduces a runtime‑based solution that separates implementation while preserving full type checking.
Installation
npm install overload-funcUsage
Define overload signatures with createOverloadedFunction and add implementations via addImple. The library matches arguments at runtime and returns correctly typed results.
import { createOverloadedFunction } from 'overload-func';
const func = createOverloadedFunction<[ (a: string) => string, (a: number, b: number) => boolean ]>();
func.addImple('string', a => a);
func.addImple('number', 'number', (a, b) => a > b);Calling func('hello') yields a string, while func(1, 2) yields a boolean, with TypeScript providing proper inference and errors for mismatched calls.
Built‑in Types
string → string number → number boolean → boolean null → null undefined → undefined symbol → symbol bigint → bigint function → Function array → any[] date → Date map → Map set → Set weakmap → WeakMap weakset → WeakSet regexp → RegExp promise → Promise error → Error object →
objectAdvanced Guide
Options such as allowMultiple let a single overload have several implementations; the last implementation’s return value is used.
const func = createOverloadedFunction<[ (a: string) => string, (a: number, b: number) => boolean ]>({ allowMultiple: true });
func.addImple('string', a => { console.log('first implementation'); return a; });
func.addImple('string', a => { console.log('second implementation'); return a.toUpperCase(); });
const r1 = func('hello'); // HELLOExtended types can be created with createExtendType to add custom keys for addImple, enabling overloads based on class instances.
class Teacher { constructor(public name: string, public salary: number) {} }
class Student { constructor(public name: string, public score: number) {} }
const extendType = createExtendType({ teacher: Teacher, student: Student });
const test = createOverloadedFunction<[ (t: Teacher) => string, (s: Student) => number ], typeof extendType>({ extendType });
test.addImple('teacher', t => t.name);
test.addImple('student', s => s.name.length);
const res1 = test(new Teacher('John', 5000)); // 'John'
const res2 = test(new Student('Alice', 90)); // 5The library also supports overloads that use this in class methods, requiring regular functions (not arrow functions) for correct this typing.
const test = createOverloadedFunction<[ (this: Test, n: number) => boolean, (this: Test, n: string, s: string) => string ]>();
test.addImple('number', function (n) { return n > this.count; });
test.addImple('string', 'string', function (n, m) { return n + m; });
class Test { count = 10; test = test; }
const t = new Test();
console.log(t.test(8)); // false
console.log(t.test('pknk', 'lll')); // 'pknklll'Conclusion
The overload‑func package provides a lightweight runtime implementation while delivering comprehensive TypeScript typings, improving developer experience for complex overload scenarios.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
