Skip to content

Instantly share code, notes, and snippets.

@mizchi
Created July 27, 2023 09:22
Show Gist options
  • Save mizchi/2d65439a6a976784791d6c3c7ab39ba1 to your computer and use it in GitHub Desktop.
Save mizchi/2d65439a6a976784791d6c3c7ab39ba1 to your computer and use it in GitHub Desktop.
type NarrowingFilter<T, U extends T> = (x: T) => x is U;
function composeFilters<A, B extends A>(f1: NarrowingFilter<A, B>): NarrowingFilter<A, B>;
function composeFilters<A, B extends A, C extends B>(
f1: NarrowingFilter<A, B>,
f2: NarrowingFilter<B, C>,
): NarrowingFilter<A, C>;
function composeFilters<A, B extends A, C extends B, D extends C>(
f1: NarrowingFilter<A, B>,
f2: NarrowingFilter<B, C>,
f3: NarrowingFilter<C, D>,
): NarrowingFilter<A, D>;
function composeFilters<A, B extends A, C extends B, D extends C, E extends D>(
f1: NarrowingFilter<A, B>,
f2: NarrowingFilter<B, C>,
f3: NarrowingFilter<C, D>,
f4: NarrowingFilter<D, E>,
): NarrowingFilter<A, E>;
function composeFilters<A, B extends A, C extends B, D extends C, E extends D, F extends E>(
f1: NarrowingFilter<A, B>,
f2: NarrowingFilter<B, C>,
f3: NarrowingFilter<C, D>,
f4: NarrowingFilter<D, E>,
f5: NarrowingFilter<E, F>,
): NarrowingFilter<A, F>;
function composeFilters<A, B extends A, C extends B, D extends C, E extends D, F extends E, G extends F>(
f1: NarrowingFilter<A, B>,
f2: NarrowingFilter<B, C>,
f3: NarrowingFilter<C, D>,
f4: NarrowingFilter<D, E>,
f5: NarrowingFilter<E, F>,
f6: NarrowingFilter<F, G>,
): NarrowingFilter<A, G>;
function composeFilters(...fs: NarrowingFilter<any, any>[]) {
return (x: any) => fs.every((f) => f(x));
}
// run
import ts from "typescript";
if (import.meta.vitest) {
function isMaybeNode(input: any): input is ts.Node {
return input?.kind !== undefined;
}
function isExpression(input: ts.Node): input is ts.Expression {
return ts.isExpression(input);
}
function isUnaryExpression(input: ts.Expression): input is ts.UnaryExpression {
return ts.isPrefixUnaryExpression(input) || ts.isPostfixUnaryExpression(input);
}
const composedFilter = composeFilters(isMaybeNode, isExpression, isUnaryExpression);
const literal = ts.factory.createNumericLiteral("1") as any;
if (composedFilter(literal)) {
const ret: ts.UnaryExpression = literal; // literal is ts.UnaryExpression
// @ts-expect-error
const ret2: string = literal;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment