4

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

1 Answer 1

1

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).

Sign up to request clarification or add additional context in comments.

2 Comments

First approach is not an option. I mean we are using typescript essentially because of the type validation. If it not able to do it with something as simple as an angular template, It loses most of its interest. Second it more acceptable I think, kind of heavy and look as a hack though. Third idea is basically React. Thanks for these ideas anyway, I will check them a little more.
:) yes, I agree with that evaluation although I didn't want to call 3rd option react directly. I'm having the same issue with angular 2 and typescript, maybe I'm missing something but so far in typescript it seems it's enough to have some part missing type info and it can screw up other parts up the chain - and in the end whatever you do it only covers some x% of the application so I live in constant anxiety of type errors not caught; It seems TS is a compromise, not a complete type safe system, which indeed it cannot fully be since the underlying run-time language is still highly dynamic

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.