Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Answer:9 function pipe #866

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions apps/angular/pipe-intermediate/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { NgFor } from '@angular/common';
import { Component } from '@angular/core';
import { WrapFnPipe } from './wrap-fn.pipe';

@Component({
standalone: true,
imports: [NgFor],
imports: [WrapFnPipe],
selector: 'app-root',
template: `
<div *ngFor="let person of persons; let index = index; let isFirst = first">
{{ showName(person.name, index) }}
{{ isAllowed(person.age, isFirst) }}
</div>
@for (person of persons; track person.name) {
<div>
{{ showName | wrapFn: person.name : $index }}
{{ isAllowed | wrapFn: person.age : $first }}
</div>
}
`,
})
export class AppComponent {
Expand Down
47 changes: 47 additions & 0 deletions apps/angular/pipe-intermediate/src/app/wrap-fn.pipe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ standalone: true, name: 'wrapFn' })
// I tried WrapFnPipe<Result> here instead of defining the Result type param
// over and over, and I was surprised that the type safety was lost!
export class WrapFnPipe implements PipeTransform {
transform<Result, ARG>(fn: (arg: ARG) => Result, arg: ARG): Result;
transform<Result, ARG1, ARG2>(
fn: (arg1: ARG1, arg2: ARG2) => Result,
arg1: ARG1,
arg2: ARG2,
): Result;
transform<Result, ARG1, ARG2, ARG3>(
fn: (arg1: ARG1, arg2: ARG2, arg3: ARG3) => Result,
arg1: ARG1,
arg2: ARG2,
arg3: ARG3,
): Result;
transform<Result, ARG1, ARG2, ARG3, ARG4>(
fn: (arg1: ARG1, arg2: ARG2, arg3: ARG3, arg4: ARG4) => Result,
arg1: ARG1,
arg2: ARG2,
arg3: ARG3,
arg4: ARG4,
): Result;
transform<Result, ARG1, ARG2, ARG3, ARG4>(
fn: (
arg1: ARG1,
arg2: ARG2,
arg3: ARG3,
arg4: ARG4,
...args: unknown[]
) => Result,
arg1: ARG1,
arg2: ARG2,
arg3: ARG3,
arg4: ARG4,
...args: unknown[]
): Result;

transform<Result>(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting this basic function was the easy part. When I saw that type safety was required, I hoped there was a way to use https://www.typescriptlang.org/docs/handbook/utility-types.html#parameterstype to handle this, but nope. Ugh.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ouch, lots of function override.

You can do shorter 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw your solution had one less override (resorting to any[] earlier). Is that what you mean? Or another idea?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

export class WrapFnPipe implements PipeTransform {
  transform<R, F extends (...args: any[]) => R>(
    func: F,
    ...args: Parameters<F>
  ): R {
    return func(...args);
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but that loses all type-safety, right? I think I had that at first, but thought we were supposed to impose type safety.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have type safety with that, I need to retry it, but I'm sure you have it.

Copy link
Contributor Author

@LMFinney LMFinney May 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried it, and you're right. There were two parts I didn't catch when I just read your comment:

  1. Using Parameters<F> is the key - it infers the args, and I missed that.
  2. The args have to be any[] instead of unknown[]. Using unknown causes a compilation error. I wouldn't have predicted that.

Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, never[] also works, and linting doesn't mind that.

fn: (...a: unknown[]) => Result,
...args: unknown[]
): Result {
return fn(...args);
}
}
Loading