Signal Forms [formField]: compiler only checks one direction, allowing unsound union FormValueControl bindings
- Dominant language
- TypeScript
- Stars
- 101k
- Forks
- 27.5k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 288
Description
### Which @angular/* package(s) are the source of the bug?
compiler, forms
### Is this a regression?
No
### Description
A custom control implementing `FormValueControl` with a union value type silently
accepts a `[formField]` binding to a field whose type is only one member of that union.
The control can then write the other member into the field, changing the runtime shape
of the developer's model signal with no diagnostic at any point.
```ts
// App.ts
myModel = signal<{roles:string}>({roles:''})
myForm = form(this.myModel)
```
```html
```
```ts
// select.ts
export class MySelect
implements FormValueControl
{
readonly value = model();
```
> now i click a button changeToArray in the app-select component
```ts
//select.ts
changeToArray() {
this.value.set(['a', 'b']);
}
```
After the control calls `value.set(['a','b'])`, the source signal holds
`{ roles: ['a','b'] }` even though `roles` is declared `string`.
### So i can see runtime Type mainpulation happens
#### Questions:
so i did look at the code base abit and i found this
the customControlCreate where i thought it has no real inheritance of the `FormField` not generic where it can be passed
> i opened the function it self, it has the parent as `FormField`
honstly i did think abit with Gemini and reialized this might be not the fix
then gemini said, it is compiler issue and it did generate some suggestion fixes, Iam not an expert in this, so i made an artifact, I thought this **might help you guys And upload it**, so you can access it
**From here : => [angular-bug-Artifact](https://angular-bug.pplx.app/)**
### Please provide a link to a minimal reproduction of the bug
https://stackblitz.com/edit/stackblitz-starters-nqxpezvp?file=package.json
### Please provide the exception or error you saw
```true
No, error were fired
```
### Please provide the environment you discovered this bug in (run `ng version`)
```true
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
Angular CLI : 22.1.3
Angular : 22.1.0
Node.js : 22.22.3
Package Manager : npm 10.8.2
Operating System : linux x64
┌───────────────────────────┬───────────────────┬───────────────────┐
│ Package │ Installed Version │ Requested Version │
├───────────────────────────┼───────────────────┼───────────────────┤
│ @angular/aria │ 22.1.1 │ ^22.1.1 │
│ @angular/build │ 22.1.3 │ ^22.1.0 │
│ @angular/cli │ 22.1.3 │ ^22.1.0 │
│ @angular/common │ 22.1.0 │ ^22.1.0 │
│ @angular/compiler │ 22.1.0 │ ^22.1.0 │
│ @angular/compiler-cli │ 22.1.0 │ ^22.1.0 │
│ @angular/core │ 22.1.0 │ ^22.1.0 │
│ @angular/forms │ 22.1.0 │ ^22.1.0 │
│ @angular/platform-browser │ 22.1.0 │ ^22.1.0 │
│ @angular/router │ 22.1.0 │ ^22.1.0 │
│ rxjs │ 7.8.2 │ ^7.8.1 │
│ typescript │ 6.0.3 │ ~6.0.3 │
└───────────────────────────┴───────────────────┴───────────────────┘
```
### Anything else?
_No response_
Contributor guide
Research direction
Start with the StackBlitz reproduction and its package.json, then inspect the compiler and forms behavior around the [formField] binding shown in App.ts and select.ts. Reproduce the union binding and verify that the invalid one-member field receives a compiler diagnostic while valid bindings remain accepted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, typescript
- Domain
- compilers, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100