Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Template compiler should treat TypeScript ! on inputs as required inputs #24879

Closed
jcomputer opened this issue Jul 13, 2018 · 9 comments
Closed
Labels
area: core Issues related to the framework runtime
Milestone

Comments

@jcomputer
Copy link

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[X] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

Currently, you cannot mark an @Input() as required a template compile time, you can just assert it is not undefined at runtime.

TypeScript supports (or requires, if you use strictPropertyInitialization) adding a ! to the end of instance property declarations which aren't initialized in-line or in the constructor to communicate to the type-checker that this variable is indeed defined, even if it doesn't appear to be.

The combination of the above two points means you end up with a sort of inconsistent state, in which you want to assert your inputs are defined in ngOnInit or ngOnChanges, yet the type-checker thinks they are already defined because you used the ! operator on their definitions.

Expected behavior

It would be nice if the template compiler could detect this operator on declarations of inputs, and take it to mean that input is required. This means the template compiler would give a (helpful) error if you used such a component but did not specify one of these required inputs, avoiding such mistakes at compile time instead of at runtime.

Minimal reproduction of the problem with instructions

http://plnkr.co/edit/7wr39D8FiEIb6JCteXr1?p=preview
(stackblitz doesn't support a new enough version of TypeScript, so I'm using plnkr)

What is the motivation / use case for changing the behavior?

In general, it would be useful to have a required parameter check as a compile-time check instead of a runtime check to both catch mistakes earlier and to reduce/simplify code (no manual checks and having to deal with checking in both ngOnInit and onChanges).

This is especially true now that TypeScript supports strictPropertyInitialization, which makes the aforementioned checks less idiomatic for TypeScript to do (since you assume the value is defined but check if it isn't defined).

Environment


TypeScript version 2.7+
@trotyl
Copy link
Contributor

trotyl commented Jul 14, 2018

Duplicate of #11904

This is totally against TypeScript semantics, the ! operator leaves no track in generated JavaScript and cannot be found in JIT. Angular is not going to be a new language.

Also could you try demo what TypeScript code should template compiler generate to support that checked? Even in AOT?

@jcomputer
Copy link
Author

jcomputer commented Jul 17, 2018

How does this go against TypeScript semantics any more than the way Angular uses decorators on classes (@Component(), @NgModule(), etc), which also leave no track in generated JavaScript? Plus, there are other types of template errors the template compiler won't catch in JIT mode but will catch in AoT mode.

The template compiler should not generate any new code, it should generate new errors (if you use a component in a template and omit a required input for it), as my link demonstrates. This is a template compile-time check, like most template compile-time checks, which may only work in AoT mode, like some other template compile-time checks.

@trotyl
Copy link
Contributor

trotyl commented Jul 17, 2018

Angular uses decorators on classes (@component(), @NgModule(), etc), which also leave no track in generated JavaScript?

Decorator is a JavaScript feature which is fully runtime-based. Angular could strip it because it's defined by Angular and have no other semantic.

but will catch in AoT mode.

This information doesn't exist in either .js or .d.ts file, but only .ts sources. Do you mean it should only work for app but not any library?

@jcomputer
Copy link
Author

It is unfortunate that this isn't output in .d.ts files (although maybe that could be a feature request for TypeScript). But this information could still be output by the Angular AoT template compiler (even for libraries) in one of two forms: (1) in the Angular template .metadata.json files or similar, or (2) as a modification to the @Input() decorator, (ie. @Input({required: true})). Again, this wouldn't work in JiT mode, but it isn't the only template compiler compile-time check that wouldn't work in JiT mode.

@trotyl
Copy link
Contributor

trotyl commented Jul 17, 2018

But this information could still be output by the Angular AoT template compiler

First of all, there’s no difference in metadata processing between AOT and JIT, only metadata retrieval. No difference can be made in how metadata looks like between AOT and JIT. Your proposal is going to against that.

Second, there will be no more .metadata.json in post-ivy structure.

but it isn't the only template compiler compile-time check that wouldn't work in JiT mode.

It is. Angular doesn’t have any additional type-check in AOT, but typescript does. So I asked what kind of TypeScript code should it generate to enable that check, since Angular won’t do it.

@matsko matsko added the area: core Issues related to the framework runtime label Jul 17, 2018
@ngbot ngbot bot added this to the needsTriage milestone Jul 17, 2018
@jcomputer
Copy link
Author

It could change @Input() to @Input({required: true}), which could be added as a feature of the template compiler (supported in both AoT mode and JiT mode) for requiring a parameter be set when a component is used.

So in AoT mode, @Input() foo!: string; gets automatically transformed to @Input({required: true}) foo: string;, whereas in JiT mode, you can either specify the second version yourself or you can just lack that compile check until you do your AoT build.

@trotyl
Copy link
Contributor

trotyl commented Jul 18, 2018

@Input() foo!: string; gets automatically transformed to @Input({required: true})

It won't, the metadata for same code must stay same in both AOT and JIT.

@mhevery
Copy link
Contributor

mhevery commented Jul 31, 2018

TypeScript can make a program not-compile by throwing a type error, but it can't make a program behave differently. In other words if you put any everywhere the application should behave same. (any everywhere is essentially JavaScript) For this reason TS can never be used as input into angular. (other than to validate types.)

Closing as not implementable.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: core Issues related to the framework runtime
Projects
None yet
Development

No branches or pull requests

4 participants