Angular Router helper for typed URL parameters.
typed-url is available as an NPM package. You can install typed-url in your Angular project as usual:
$ npm install typed-url --save
It allows applying type constraints to angular router URL route parameters.
Consider the URL /user/:id/:name
. One could wish to only allow integers
numbers in place of :id
typed-url makes this posible.
Build-in types
type | syntax | result type |
---|---|---|
integer | 'int' | number |
string | 'string' | string |
regex | /^regex$/ | RegExpMatchArray |
enum | ['val1', 'val2'] | string |
custom validators | new CustomTypeValidator() | depends on you 😁 |
** app-routing.module.ts **
import { typedUrl } from 'typed-url';
const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' },
{ path: 'cars-list',
children: [
// this route only matchs for valid url params
{
matcher: typedUrl<CarListRouteParams>(':sort/:sortDir/:color/:constructed/:make', {
sort: ['name', 'make', 'constructed'],
sortDir: ['asc', 'desc'],
color: /^([1-9a-f]{6})$/, // regex produces the result type `RegExpMatchArray`
constructed: 'int',
make: 'string'
}),
component: CarListComponent
},
// catch all invalid and redirect back to default filter.
{ path: '**', redirectTo: 'name/asc/red/2019/audi' }
]
},
{ path: '**', component: PageNotFoundComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
** CarListComponent **
import { getTypedParams } from 'typed-url';
export interface CarListRouteParams {
sort: 'name' | 'make' | 'constructed';
sortDir: 'asc' | 'desc';
color: RegExpMatchArray;
constructed: number;
make: string;
}
@Component({selector: 'car-list'})
export class CarListComponent {
constructor(
public route: ActivatedRoute
) {
this.route.paramMap
.pipe(getTypedParams<CarListRouteParams>())
.subscribe(_ => {
// all params have the correct type
const sort = _.sort;
const sortDir = _.sortDir;
const color = _.color[0]; // because it's of type `RegExpMatchArray`
const constructed = _.constructed;
const make = _.make;
import { isNumber } from 'util';
console.assert( isNumber(constructed) ); // shows -> true
});
}
}
For the above example one could write a custom TypeValidator
for the CarListRouteParams.color
field.
class HexColorValidator extends TypeValidator {
matches(value: string): boolean {
return /^([1-9a-f]{6})$/.test(value);
}
parse(value: string) {
return `#${value}`;
}
}
// and use it like:
const routes = [
{
matcher: typedUrl<ColorRouteParams>(':color', {
color: new HexColorValidator()
}),
component: ColorComponent
}
];
interface ColorRouteParams {
color: string;
}