Created
November 27, 2024 00:32
-
-
Save trvswgnr/3882992a785af84d9e8459c7615b8f52 to your computer and use it in GitHub Desktop.
partial application typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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