TypeScriptadvanced
export const createMethodGuard = <M extends string>(allowed: M[], fallback: NoInfer<M>) => {
const allowedSet = new Set<string>(allowed);
return (method: string): M => (allowedSet.has(method) ? (method as M) : fallback);
};
Prevent TypeScript from widening generic arguments when you need stable inference.
TypeScriptadvanced
export class QueryBuilder<Shape extends Record<string, unknown> = Record<string, never>> {
private constructor(private readonly clauses: Shape) {}
static create(): QueryBuilder<Record<string, never>> {
return new QueryBuilder({});
Make each .where() call widen the builder's tracked return type by exactly the key and value just added, so build() is never underspecified.
TypeScriptadvanced
export function parseValue(input: string): string;
export function parseValue(input: number): number;
export function parseValue(input: string | number): string | number {
return typeof input === "string" ? input.trim() : Math.round(input);
}
Same function, two type-safe shapes: distinct return types per input type via overloads, versus one T-preserving signature via a generic.
TypeScriptadvanced
type EventMap = Record<string, unknown>;
export class TypedEmitter<Events extends EventMap> {
private listeners: { [K in keyof Events]?: Array<(payload: Events[K]) => void> } = {};
Make on() and emit() reject mismatched event names and payloads at compile time, from one map type instead of per-event overloads.
TypeScriptadvanced
const asConstTuple = <const T extends readonly string[]>(...values: T): T => values;
export const statuses = asConstTuple("pending", "active", "done");
export type Status = (typeof statuses)[number];
Stop a generic function from widening ['pending','active'] to string[] on the way in, without forcing every caller to write as const.
TypeScriptadvanced
type AsyncReturnType<Fn extends (...args: never[]) => unknown> = Fn extends (
...args: never[]
) => Promise<infer R>
? R
: Fn extends (...args: never[]) => infer R
Build a return-type extractor that also unwraps the Promise, so async and sync functions land on the same resolved type.