angular/packages/forms/test
Dylan Hunn e441ff44b4 fix(forms): Prevent FormBuilder from distributing unions to control types. (#45942)
Previously, using `FormBuilder` with a union type would produce unions of *controls*:

```
// `foo` has type `FormControl<string>|FormControl<number>`.
const c = fb.nonNullable.group({foo: 'bar' as string | number});
```

This actually works in many cases, due to how extraordinarily powerful Typescript's distributive types are (e.g. `value` still has type `string|number`), but it is subtly incorrect. Here is a code example that exposes the reason the inference is incorrect. It exploits the fact that Typescript will not "un-distribute" a type, producing an obviously spurious error:

```
// fc gets an inferred distributive union type `FormControl<string> | FormControl<number>`
let fc = c.controls.foo;
// Error: Type 'FormControl<string | number>' is not assignable to type 'FormControl<string> | FormControl<number>'.
fc = new FormControl<string|number>('', {initialValueIsDefault: true});
```

Instead, we want the union to apply to the *values*:

```
// `foo` should have type `FormControl<string|number>`.
const c = fb.nonNullable.group({foo: 'bar' as string | number});
```

Essentially, we want to prevent Typescript from distributing the type. [As specified in the handbook](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#distributive-conditional-types):

> Typically, distributivity is the desired behavior. To avoid that behavior, you can surround each side of the extends keyword with square brackets.

This PR applies this suggestion to `FormBuilder`'s type inference.

Fixes #45912.

PR Close #45942
2022-05-10 12:36:37 -07:00
..
BUILD.bazel build: switch devmode output to es2015 (#44505) 2022-01-05 23:20:20 +00:00
directives_spec.ts fix(forms): improve error message for invalid value accessors (#45192) 2022-03-15 13:26:03 -07:00
form_array_spec.ts feat(forms): Implement strict types for the Angular Forms package. (#43834) 2022-04-12 17:37:04 +00:00
form_builder_spec.ts fix(forms): Allow NonNullableFormBuilder to be injected. (#45904) 2022-05-09 17:31:48 -07:00
form_control_spec.ts refactor(forms): Move FormControl to an overridden exported constructor. (#44316) (#44806) 2022-01-31 22:48:23 +00:00
form_group_spec.ts feat(forms): Implement strict types for the Angular Forms package. (#43834) 2022-04-12 17:37:04 +00:00
reactive_integration_spec.ts fix(forms): not picking up disabled state if group is swapped out and disabled (#43499) 2022-03-28 09:26:19 -07:00
template_integration_spec.ts feat(core): triggerEventHandler accept optional eventObj (#45279) 2022-03-09 13:51:54 -08:00
typed_integration_spec.ts fix(forms): Prevent FormBuilder from distributing unions to control types. (#45942) 2022-05-10 12:36:37 -07:00
util.ts refactor(forms): refactor common validators used in unit tests (#38020) 2020-07-22 20:42:43 -07:00
validators_spec.ts fix(forms): Correct empty validator to handle objects with a property length: 0. (#33729) 2022-02-03 23:15:27 -08:00
value_accessor_integration_spec.ts fix(forms): ensure OnPush ancestors are marked dirty when the promise resolves (#44886) 2022-01-31 21:38:39 +00:00