angular: HttpParams of New HttpClient Doesn't Support Number, Boolean and Date
I’m submitting a…
[x] Regression (a behavior that used to work and stopped working in a new release)
Current behavior
ERROR in /path/to/heroes.service.ts(23,44): error TS2345: Argument of type '{ params: { groupId: number; }; }' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
Types of property 'params' are incompatible.
Type '{ groupId: number; }' is not assignable to type 'HttpParams | { [param: string]: string | string[]; }'.
Type '{ groupId: number; }' is not assignable to type '{ [param: string]: string | string[]; }'.
Property 'groupId' is incompatible with index signature.
Type 'number' is not assignable to type 'string | string[]'.
Expected behavior
No errors should occur.
Minimal reproduction of the problem with instructions
// heroes-query-params.model.ts
export class HeroesQueryParams {
groupId: number;
country: string;
dead: boolean;
}
// heroes.component.ts
const params: HeroesQueryParams = {
groupId: 1,
name: 'US',
dead: false
};
this.heroesService.getHeroes(params).subscribe((heroes: Heroes) => {
console.log(heroes);
});
// heroes.service.ts
import { HttpClient } from '@angular/common/http';
// ...
getHeroes(params: HeroesQueryParams): Observable<Heroes> {
return this.httpClient.get<Heroes>('/path/to/heroes', {
params: params // ERROR
});
}
To cut a long story short, new HttpClient
, which is imported from @angular/common/http
, doesn’t support non-string values in query params. This is related to numbers, booleans, dates etc. That’s why I should use old one, write some transform utils or just .toString()
.
What is the motivation / use case for changing the behavior?
It worked previously.
Environment
Angular version: 6.0.0
Browser:
- [x] Chrome (desktop) version 66
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 23
- Comments: 21 (4 by maintainers)
Commits related to this issue
- feat(common): allow number or boolean as http params Allows to use number and boolean directly as HTTP params, instead of having to convert it to string first. Before: this.http.get('/api/confi... — committed to cexbrayat/angular by cexbrayat 3 years ago
- feat(common): allow number or boolean as http params Allows to use number and boolean directly as HTTP params, instead of having to convert it to string first. Before: this.http.get('/api/confi... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params Allows to use number and boolean directly as HTTP params, instead of having to convert it to string first. Before: this.http.get('/api/config... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params Allows to use number and boolean directly as HTTP params, instead of having to convert it to string first. Before: this.http.get('/api/config... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params Allows to use number and boolean directly as HTTP params, instead of having to convert it to string first. Before: this.http.get('/api/config... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params Allows to use number and boolean directly as HTTP params, instead of having to convert it to string first. Before: this.http.get('/api/config... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params Allows to use number and boolean directly as HTTP params, instead of having to convert it to string first. Before: this.http.get('/api/config... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params This change fixes an incompatibility between the old `@angular/http` package and its successor (`@angular/common/http`) by re-introducing the types... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params This change fixes an incompatibility between the old `@angular/http` package and its successor (`@angular/common/http`) by re-introducing the types... — committed to cexbrayat/angular by cexbrayat 3 years ago
- fix(common): allow number or boolean as http params This change fixes an incompatibility between the old `@angular/http` package and its successor (`@angular/common/http`) by re-introducing the types... — committed to cexbrayat/angular by cexbrayat 3 years ago
This is for those who want fast solution.
FIX THIS!
@nhays89, instead of yelling you’d better create pull request with fix.
HttpParams is immutable. set() creates and returns a new HttpParams instance, without mutating the instance on which set() is called. So the code should be
const params = new HttpParams().set(‘status’, status);
This is not a regression, since
HttpClient
is explicitly not API-compatible with the old@angular/http
library. However, it is something we should support.@gautamkrishnar, I think there won’t be any. It seems like Angular team sees us using
new HttpParams().append(key, nonStringValue.toString())
each time, so I just proceed with my solution above.HttpParams is immutable. set() creates and returns a new HttpParams instance, without mutating the instance on which set() is called. So the code should be
const params = new HttpParams().set(‘status’, status);
this OOP enthusiasm is definitely went too far in this case
Still no update on this?
Finally, here’s the solution.
Here I used two helper methods from Lodash.
@AlainD-, thanks for pointing this out. It really depends on the client-server contract. For example, maybe you want
Date.now().toString()
instead ofnew Date().toISOString()
. In this solution I wanted to mimic AngularJS behavior, so I need to take a look at its date auto convertion and replicate it. What’s even more important, is to safely handle reference types:Object
,Array
andFunction
. Arrays work as expected, because[1, 2, 3].toString()
returns'1,2,3'
, but it’s not the case for objects and functions. Probably objects auto conversion should be justJSON.stringify({ foo: 'bar' })
. And for functions I think we may leavetoString()
. What’s your opinion? Am I overcomplicating this?@ericmartinezr seems like #19595 wont be updated
See https://github.com/angular/angular/pull/19595