rpbeukes / angular-typesafe-reactive-forms-helper

Get intellisense when using Angular Reactive Forms, no more misspelled property names, refactoring Reactive Forms is back to a trivial IDE rename task.
https://www.npmjs.com/package/angular-typesafe-reactive-forms-helper
MIT License
10 stars 3 forks source link

update helper to be compatible with angular 14 #350

Open mrs-cp opened 2 years ago

mrs-cp commented 2 years ago

we are currently using your fantastic helper in one of our projects. angular 14 now features an option to make forms typesafe, however, we still like your option way more und would love to continue using it instead of refactoring the whole project to fit the criteria of angular's new typesafe forms. any chance you might update the helper?

rpbeukes commented 2 years ago

Hi @mrs-cp,

I have not touched the new Angular stuff yet, so it will be a slow process. Maybe I'll jump straight to 14 and skip all the older versions.

Glad this little implementation is useful to you.

I'll have to give this project a bit more love ❤️ 😃. I'll get cracking next week.

Thanx for reaching out.

rpbeukes commented 2 years ago

Had a quick look at this and I need to investigate more, as the Angular base classes have changed to support the new Type safe React forms.

I will have to get an ng14 working copy of the new TypeSafe implementation and then evaluate if angular-typesafe-reactive-forms-helper would still be useful.

Not a quick fix, I'm afraid 😱

mrs-cp commented 2 years ago

Hey, no worries, we figured as much and have found a solution for now. Having said that, we're looking forward to seeing what you'll come up with. 💪

rpbeukes commented 2 years ago

@mrs-cp do you maybe have an open source example of how you folks tackled/solved the issue. Would help me with my investigation, please? 🙂

mrs-cp commented 2 years ago

we have used this approach: https://netbasal.com/typed-reactive-forms-in-angular-no-longer-a-type-dream-bf6982b0af28 Netanel Basal suggested to use his snippet

export type ControlsOf<T extends Record<string, any>> = {
  [K in keyof T]: T[K] extends Record<any, any>
  ? FormGroup<ControlsOf<T[K]>>
  : FormControl<T[K]>;
};

which we have tweaked to make it work with FormArrays, too:

type NonUndefined<T> = T extends undefined ? never : T;

export type ControlsOf<T extends Record<string, any>> = {
  [K in keyof T]: NonUndefined<T[K]> extends AbstractControl
    ? T[K]
    : NonUndefined<T[K]> extends Array<infer R>
      ? FormArray<AbstractControlOf<R>>
      : NonUndefined<T[K]> extends Record<string, any>
        ? FormGroup<ControlsOf<NonUndefined<T[K]>>>
        : FormControl<T[K]>;
};

export type AbstractControlOf<T> = NonUndefined<T> extends Array<infer R>
    ? FormArray<AbstractControlOf<R>>
    : NonUndefined<T> extends Record<string, any>
      ? FormGroup<ControlsOf<NonUndefined<T>>>
      : FormControl<T>;

It's working so far ...

rpbeukes commented 2 years ago

Nice! Will see if we can bake it in 😊.

Thanx for the share, much appreciated.

Schaussi commented 2 years ago

Thanks for sharing - unfortunately, like in the example above, it does not work with Date types. image

@mrs-cp Would be great if you could give us a hint how to solve this.

Edit: Not fully tested yet, but might work:


type NonUndefined<T> = T extends undefined ? never : T;

export type ControlsOf<T extends Record<string, any>> = {
  [K in keyof T]: NonUndefined<T[K]> extends AbstractControl
  ? T[K]
  : NonUndefined<T[K]> extends Array<infer R>
  ? FormArray<AbstractControlOf<R>>
  : NonUndefined<T[K]> extends Date
  ? FormControl<T[K]>
  : NonUndefined<T[K]> extends Record<string, any>
  ? FormGroup<ControlsOf<NonUndefined<T[K]>>>
  : FormControl<T[K]>;
};

export type AbstractControlOf<T> = NonUndefined<T> extends Array<infer R>
  ? FormArray<AbstractControlOf<R>>
  : NonUndefined<T> extends Record<string, any>
  ? FormGroup<ControlsOf<NonUndefined<T>>>
  : FormControl<T>;
leandrotassi commented 1 year ago

Thanks for sharing - unfortunately, like in the example above, it does not work with Date types. image

@mrs-cp Would be great if you could give us a hint how to solve this.

Edit: Not fully tested yet, but might work:


type NonUndefined<T> = T extends undefined ? never : T;

export type ControlsOf<T extends Record<string, any>> = {
  [K in keyof T]: NonUndefined<T[K]> extends AbstractControl
  ? T[K]
  : NonUndefined<T[K]> extends Array<infer R>
  ? FormArray<AbstractControlOf<R>>
  : NonUndefined<T[K]> extends Date
  ? FormControl<T[K]>
  : NonUndefined<T[K]> extends Record<string, any>
  ? FormGroup<ControlsOf<NonUndefined<T[K]>>>
  : FormControl<T[K]>;
};

export type AbstractControlOf<T> = NonUndefined<T> extends Array<infer R>
  ? FormArray<AbstractControlOf<R>>
  : NonUndefined<T> extends Record<string, any>
  ? FormGroup<ControlsOf<NonUndefined<T>>>
  : FormControl<T>;

I also had the same problem. Managed to solve?

mrs-cp commented 1 year ago

hi sorry, somehow missed this question. I've just checked @leandrotassi's solution and it works like a charm :)

thanks for the hint re date types and the solution