update: typing shadowRoot from any type
Description
shadowRoot: any makes all related properties / methods return to any. This changes reduce count of variables & methods typed as any and prevent unstable usage from nullable variables / methods return.
⚠️ Test Required! ⚠️
All features (even bugs of current version) should have same behavior / result / looks.
Typing pattern
this.shadowRoot?.querySelector() / this.shadowRoot?.getElementById()
example: <mwc-button>
import {Button} from '@material/mwc-button';
import component with exported class sometimes this statement may cause unexpected error
// querySelector with tag name automatically infer proper type for element
this.shadowRoot?.querySelector('mwc-button');
//. querySelector with id or class name does not infer proper tag name
this.shadowRoot?.querySelector('#button-id') as Button; // type casting
// for querySelectorAll
this.shadowRoot?.querySelectorAll<Button>('mwc-button') as NodeListOf<Button>; // type casting
use one of the above patterns for using typed result of querySelector / getElementId
this.shadowRoot?.querySelector('#button-id') as HTMLElementTagNameMap['mwc-button'];
in case of typing element without changing
import ... from ...statement the above type casting could avoid unexpected error / behavior caused byimport ... from ...statement
@query decorator
if there are many (over twice referencing) querySelector / getElementById calls, we can optimize and reduce code by using @query decorator
before declaration
@property({type: Object}) button = Object();
firstUpdated() {
this.button = this.shadowRoot?.querySelector('#button-id');
}
after
@query('#button-id') button!: Button;
NOTE: specify !(explicit unwrap) operator required
Type importing / declaring
I found some issues while importing component with type (which occurred in import ... from ... statements)
The problem above is imported component with types not rendered properly and also runtime error occurs.
Also, with no type declaration component (related to vaadin-* component), can be used like same way.
So I resolve this issue like this:
type Button = HTMLElementTagNameMap['mwc-button'];
type LablupCodemirror = HTMLElementTagNameMap['lablup-codemirror'];
this.shadowRoot?.querySelector('#some-button') as Button;
this.shadowRoot?.getElementById('editor') as LablupCodemirror;
related issue: #1357
Changes
- remove
shadowRoot: anyfrom all components undersrc/components(exceptsession-launcher-legacy)- now shadowRoot typed as
ShadowRoot | null(it is lit-element's default)
- now shadowRoot typed as
- resolve type errors:
- by adding optional chaining / type casting
- by correcting logical mistakes
- by declaring @query decorators for render tree elements
- ...and more proper ways
- specify element tag types for not registered tags in global namespace
- backend-ai-change-forgot-password-view
- backend-ai-email-verification-view
- logic update:
- incorrect logic (e.g.
for ... ofstatement with NodeListOf (which is querySelectorAll's return type) - remove unused lifecycle callback (e.g. empty constructor)
- ...and more
- incorrect logic (e.g.
- write TODO comments:
- unresolved any types
- logics need to refactor
- restricted access modifier usages (e.g. protected / private properties assignment, call, reference)
- etc.
@lizable I wrote FIXME comment to all related components.
Total allocation pane is broken.
It works for me.
OK then, go ahead!
Finally! Thanks to all participants 😄