Skip to content

Instantly share code, notes, and snippets.

@shun-shobon
Created December 27, 2022 17:07
Show Gist options
  • Save shun-shobon/5f9846ce269a6b0ac5179a1f7a49e831 to your computer and use it in GitHub Desktop.
Save shun-shobon/5f9846ce269a6b0ac5179a1f7a49e831 to your computer and use it in GitHub Desktop.
オーバーロード無しでfp-ts風のpipe関数を実装
type Fn<T, U> = (_: T) => U;
type TopFn = Fn<never, unknown>;
type TopFns = ReadonlyArray<TopFn>;
type AssertPipeFns<Arg, Fns extends TopFns> = Fns extends [] ? true
: Fns extends [
infer HeadFn extends TopFn,
...infer RestFn extends TopFns,
] ? HeadFn extends Fn<Arg, infer NextArg> ? AssertPipeFns<NextArg, RestFn>
: false
: false;
interface THIS_FUNCION_IS_INVALID_TYPE extends Fn<unknown, never> {}
type FindInvalidFn<Arg, Fns extends TopFns, Return extends TopFns = []> =
Fns extends [] ? Return
: Fns extends [
infer HeadFn extends TopFn,
...infer RestFn extends TopFns,
]
? HeadFn extends Fn<Arg, infer NextArg>
? FindInvalidFn<NextArg, RestFn, [...Return, HeadFn]>
: FindInvalidFn<Arg, RestFn, [...Return, THIS_FUNCION_IS_INVALID_TYPE]>
: never;
type PipeReturn<T, Fns extends TopFns> = Fns extends
[...TopFns, infer LastFn extends TopFn] ? ReturnType<LastFn> : T;
declare function pipe<
T,
Fns extends TopFns,
>(
x: T,
...fns: AssertPipeFns<T, Fns> extends true ? Fns : FindInvalidFn<T, Fns>
): PipeReturn<T, Fns>;
const a: boolean = pipe(
1,
(x: number) => x * 2,
(x: number) => x.toString(),
(x: string) => x === "2",
);
// Type Error
const b: boolean = pipe(
1,
(x: number) => x * 2,
(x: string) => x.toString(),
(x: string) => x === "2",
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment