Yoann Augen
Yoann Augen

Reputation: 2036

Validate Input with custom type Angular

I have a component with an Input defined as a custom type.

@Input() public labelSize: 'small' | 'normal' | 'large'  = 'normal';

But apparently I can pass any kind of parameter to the component tag. I will never have any kind of error/warning.

<my-component labelSize="whatever"></my-component>

I can event pass a number

<my-component labelSize=12345></my-component>

I expected the typescript compiler or angular to give me some feedback on this kind of error.

I'm supposed to validate myself the type of all the Inputs of my components?

Any best practices?

Thanks

Upvotes: 4

Views: 1221

Answers (1)

Ovidiu Dolha
Ovidiu Dolha

Reputation: 5413

The angular templates are HTML and are not in any way hooked into typescript for checking this. And even in typescript it's allowed to bypass the type declaration, e.g. this.labelSize = 'whatever' as any.

In the end the code is still javascript. And in the templates is just like using plain javascript from the start.

If you really want to catch mismatches up front, some possible solutions are:

1. Validation

As already suggested, do a manual validation or use a validation library to specify constraints, e.g. https://validatejs.org/

By the way, you can also use a Pipe to add validation on the fly on any of your values and have more clarity on your html.

2. Config objects

You can capture the configuration of components where types are important in an object, as such

@Input() public config: {
  labelSize: 'small' | 'normal' | 'large';
} = { labelSize: 'normal' }

and then bind the input to myCompConfig:

<my-component [config]="myCompConfig"></my-component>

then in your controller where you use it

this.myCompConfig = { labelSize: 'whatever' } // error <- type is enforced now

3. TS for templates

You can use TS instead of HTML for templates, and assist it with some type info:

Share your type first

export type LabelSize = 'small' | 'normal' | 'large'

@Input() public labelSize: LabelSize = 'normal';

my-template.ts

const labelSize: LabelSize = 'whatever' // error <- type is enforced 

export const template = `
    <my-component labelSize=${labelSize}></my-component>`
`;

then in your component use it directly

import { template } from './my-template.ts';
@Component({ selector: 'something', template })

Note this can also be extracted into a factory-approach for creating parts of your temples, e.g. you can have a factory for creating this element based on a labelSize param (and this param can have type info).

Upvotes: 1

Related Questions