Skip to content

Commit

Permalink
improve-pipeline-type-inference
Browse files Browse the repository at this point in the history
  • Loading branch information
uriva committed Jan 8, 2025
1 parent 0c1c20e commit d5f1a70
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 15 deletions.
9 changes: 6 additions & 3 deletions src/composition.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,13 @@ const _3: Promise<number> = pipe(
(y: number) => y,
)(1);

// failing typing tests:
const f = pipe(<T>(x: T) => x);
f(8);

// Generics inference
const _4: number = pipe((y: number) => y, <T>(x: T) => x)(1);

// Generics can infer by the last function
// const _4: number = pipe((y: number) => y, <T >(x: T) => x)(1);
// failing typing tests:

// Generics understands contextual extends
// const _5 = <Fn extends (x: string) => number>(f: Fn) => {
Expand Down
12 changes: 5 additions & 7 deletions src/composition.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { reverse } from "./array.ts";
import { ComposeMany } from "./composeTyping.ts";
import { not } from "./operator.ts";
import { isPromise } from "./promise.ts";
import { reduce } from "./reduce.ts";
Expand All @@ -7,9 +8,8 @@ import type {
AnyAsync,
AsyncFunction,
Func,
Last,
ParamOf,
ReturnTypeUnwrapped,
PromisifyFunction,
UnaryFnUntyped,
} from "./typing.ts";

Expand All @@ -30,10 +30,9 @@ type ValidPipe<FS extends Func[]> = FS extends
? [ValidCompose<F1, F2>, ...ValidPipe<[F2, ...Rest]>] // tuple length >= 2
: FS; // tuple length < 2

type Pipeline<Fs extends Func[]> = (
...x: Parameters<Fs[0]>
) => Fs extends AnyAsync<Fs> ? Promise<ReturnTypeUnwrapped<Last<Fs>>>
: ReturnType<Last<Fs>>;
type Pipeline<Fs extends Func[]> = Fs extends AnyAsync<Fs>
? PromisifyFunction<ComposeMany<Fs>>
: ComposeMany<Fs>;

const pipeWithoutStack = <Fs extends Func[]>(
...fs: ValidPipe<Fs>
Expand Down Expand Up @@ -86,7 +85,6 @@ type Reversed<Tuple> = Tuple extends [infer Head, ...infer Rest]
export const compose = <Fs extends Func[]>(
...fs: Fs
): Fs extends ValidPipe<Reversed<Fs>> ? Pipeline<Reversed<Fs>> : never =>
// @ts-expect-error reason: TODO - fix typing
pipe(...reverse(fs));

export const after =
Expand Down
1 change: 1 addition & 0 deletions src/io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const batch = <
const keyToTimeout: Record<TaskKey, Timeout> = {} as Record<TaskKey, Timeout>;

const clearAndExecute = (key: TaskKey) => {
// @ts-expect-error not sure what's wrong here
executeTasks(execute)(keyToTasks[key]);
clearTimeout(keyToTimeout[key]);
delete keyToTimeout[key];
Expand Down
7 changes: 2 additions & 5 deletions src/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,5 @@ export const each = <F extends UnaryFnUntyped>(f: F) =>
if (results.length) return Promise.all(results).then();
};

export const mapCat = <T, G>(
f: Unary<T, G>,
) =>
// @ts-expect-error ts cannot reason about this
(x: T[]): G => pipe(map(f), reduce((a, b) => a.concat(b), () => []))(x);
export const mapCat = <T, G>(f: Unary<T, G>) => (x: T[]): G =>
pipe(map(f), reduce((a, b) => a.concat(b), () => []))(x);
4 changes: 4 additions & 0 deletions src/typing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ export type ReturnTypeUnwrapped<F extends Func> = F extends AsyncFunction

// deno-lint-ignore no-explicit-any
export type UnaryFnUntyped = (input: any) => any;

export type PromisifyFunction<F extends Func> = (
...args: Parameters<F>
) => Promise<ReturnType<F>>;

0 comments on commit d5f1a70

Please sign in to comment.