Skip to content

Instantly share code, notes, and snippets.

@trvswgnr
Created November 27, 2024 00:32
Show Gist options
  • Save trvswgnr/3882992a785af84d9e8459c7615b8f52 to your computer and use it in GitHub Desktop.
Save trvswgnr/3882992a785af84d9e8459c7615b8f52 to your computer and use it in GitHub Desktop.
partial application typescript
import type { Expect, Equal, IsAny, IsUnknown } from "type-testing";
import { Solution } from "./solution";
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
type AnyArray = any[];
type PartialApplicationHelper<T extends AnyArray, R> = <A extends Partial<T>>(
...args: A
) => A extends AnyArray
? A["length"] extends T["length"]
? R
: PartialApplicationHelper<ShiftN<T, A["length"]>, R>
: never;
type PartialApplication<T extends (...args: AnyArray) => unknown> =
PartialApplicationHelper<Parameters<T>, ReturnType<T>>;
type ToArray<T extends number, R extends AnyArray = []> = R["length"] extends T
? R
: ToArray<T, [...R, unknown]>;
type Subtract<M extends number, S extends number> = ToArray<M> extends [
...ToArray<S>,
...infer Rest,
]
? Rest["length"]
: never;
type ShiftN<T extends AnyArray, N extends number> = T extends [
infer _First,
...infer Rest extends AnyArray,
]
? N extends 0
? T
: ShiftN<Rest, N extends 0 ? 0 : Subtract<N, 1>>
: never;
// Sample function with multiple arguments
const f = (arg1: number, arg2: string, arg3: boolean, arg4: Date) => {
return `${arg1}, ${arg2}, ${arg3}, ${arg4.toDateString()}`;
};
const partial = <T extends (...args: Parameters<T>) => ReturnType<T>>(
fn: T,
) => {
// TODO: a real implementation here
return fn as unknown as PartialApplication<T>;
};
const z: PartialApplication<typeof f> = partial(f);
// Example calls: all should not be errors
const result1 = z(0, "a", true, new Date()); // Direct call
const result2 = z(0)("a", true, new Date()); // Partially applied
const result3 = z(0, "a", true)(new Date()); // Another partial
const result4 = z()(0, "a", true)(new Date()); // Another partial
const result5 = z(0, "a", true); // fn missing last arg
type IsUnknownOrAny<T> = IsUnknown<T> extends true
? true
: IsAny<T> extends true
? true
: false;
type HasUnknownOrAny<T extends readonly unknown[]> = T extends [
infer First,
...infer Rest,
]
? IsUnknownOrAny<First> extends true
? true
: HasUnknownOrAny<Rest>
: false;
type t0 = Expect<Equal<HasUnknownOrAny<Parameters<typeof f>>, false>>;
type t1_actual = [
typeof result1,
typeof result2,
typeof result3,
typeof result4,
typeof result5,
];
type t1_expected = [
string,
string,
string,
string,
PartialApplicationHelper<[x: Date], string>,
];
type t1 = Expect<Equal<t1_actual, t1_expected>>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment