Diesen Sommer haben Roma und ich eine Reihe von Tweets mit hilfreichen Angular-Tipps und Tricks veröffentlicht. Diese Initiative wurde von der Community sehr begrüßt und ich beschloss, einen zusammenfassenden Artikel zu schreiben. Hier sind meine 5 Empfehlungen, die ich Entwicklern mitteilen möchte. Diese Tipps werden durch konkrete Beispiele aus meinem Twitter untermauert . Sie helfen Ihnen, Ihre Fähigkeiten zu verbessern, oder geben Ihnen zumindest ein paar praktische Tipps.

1. Verstehen Sie den Änderungsprüfungsmechanismus
Im Internet gibt es viele ausführliche Artikel zum Überprüfen von Änderungen in Angular. Zum Beispiel dieser. Lassen Sie uns also einfach die Grundlagen auffrischen und zu den Tipps kommen.
Die Grundlagen
Angular : Default OnPush. tick . Zone.js, . view , .
Default vs OnPush
, Default. , , OnPush. . , OnPush .
@HostListener Angular OnPush. , RxJS? ChangeDetectorRef markForCheck(), . async , . .
:
<div *ngIf="stream$ | async as result">
…
</div>, falsy-? ngIf . , :
@Directive({
selector: "[ngLet]"
})
export class LetDirective<T> {
@Input()
ngLet: T;
constructor(
@Inject(ViewContainerRef) container: ViewContainerRef,
@Inject(TemplateRef) templateRef: TemplateRef<LetContext<T>>
) {
container.createEmbeddedView(templateRef, new LetContext<T>(this));
}
}NgZone
OnPush, . NgZone .runOutsideAngular(). . Default . , mousemove scroll. RxJS- : — , — , :
class ZonefreeOperator<T> implements Operator<T, T> {
constructor(private readonly zone: NgZone) {}
call(observer: Observer<T>, source: Observable<T>): TeardownLogic {
return this.zone.runOutsideAngular(
() => source.subscribe(observer)
);
}
}
export function zonefull<T>(zone: NgZone): MonoTypeOperatorFunction<T> {
return map(value => zone.run(() => value));
}
export function zonefree<T>(zone: NgZone): MonoTypeOperatorFunction<T> {
return source => source.lift(new ZonefreeOperator(zone));
},
@HostListener, —EventManagerPlugin. open-source- ng-event-plugins. . .
2. RxJS
RxJS — . , . , —
— . , , :
, , . CSS RxJS:
@Directive({
selector: "[sticky]",
providers: [DestroyService]
})
export class StickyDirective {
constructor(
@Inject(DestroyService) destroy$: Observable<void>,
@Inject(WINDOW) windowRef: Window,
renderer: Renderer2,
{ nativeElement }: ElementRef<HTMLElement>
) {
fromEvent(windowRef, "scroll")
.pipe(
map(() => windowRef.scrollY),
pairwise(),
map(([prev, next]) => next < THRESHOLD || prev > next),
distinctUntilChanged(),
startWith(true),
takeUntil(destroy$)
)
.subscribe(stuck => {
renderer.setAttribute(
nativeElement,
"data-stuck",
String(stuck)
);
});
}
}RxJS Angular- . RxJS , . , , .
, . , RxJS, — . - . ( ).
3. TypeScript
Angular- TypeScript. , , . strict: true. . cannot read property of null undefined is not a function.
TypeScript — , , , . , API. . RxJS- fromEvent:
// currentTarget
export type EventWith<
E extends Event,
T extends FromEventTarget<E>
> = E & {
readonly currentTarget: T;
};
// fromEvent
export function typedFromEvent<
E extends keyof GlobalEventHandlersEventMap,
T extends FromEventTarget<EventWith<GlobalEventHandlersEventMap[E], T>>
>(
target: T,
event: E,
options: AddEventListenerOptions = {},
): Observable<EventWith<GlobalEventHandlersEventMap[E], T>> {
return fromEvent(target, event, options);
} , , currentTarget — , .
API, , , . , .
TypeScript. , . : any. , unknown.
TypeScript, . . , , , : , , — number. TypeScript , runtime :
export function assert<T, K extends keyof T>(
assertion: (input: T[K]) => boolean,
messsage: string
): PropertyDecorator {
return (target, key) => {
Object.defineProperty(target, key, {
set(this: T, initialValue: T[K]) {
let currentValue = initialValue;
Object.defineProperty(this, key, {
get(): T[K] {
return currentValue;
},
set(this: T, value: T[K]) {
console.assert(assertion(value), messsage);
currentValue = value;
}
});
}
});
};
} , super()? Angular , :
— . Web Audio API Angular, . .
4. Dependency Injection.
DI — , Angular . , . .
, DI, .
RxJS
, RxJS. , , , . Angular :
@Injectable()
export class DestroyService extends Subject<void> implements OnDestroy {
ngOnDestroy() {
this.next();
this.complete();
}
} DI. requestAnimationFrame . . , :
DI — . window navigator — Angular Universal . , . . . WINDOW DOCUMENT:
export const WINDOW = new InjectionToken<Window>(
'An abstraction over global window object',
{
factory: () => {
const {defaultView} = inject(DOCUMENT);
if (!defaultView) {
throw new Error('Window is not available');
}
return defaultView;
},
},
);, open-source-, . Angular Universal - . , , - .
. DI . .
5. ,
Angular . . . : . , , .

— « »? ngOnChanges . -, , , - .
— . - , .
— , . . , . , — , .
, , .
Template reference variables
Angular @ViewChild. , :
<input #input>
<button (click)="onClick(input)">Focus</button>template reference variable , . . .
, DOM-, ? @ViewChild(MyComponent, {read: ElementRef}), , exportAs:
@Directive({
selector: '[element]',
exportAs: 'elementRef',
})
export class ElementDirective<T extends Element> extends ElementRef<T> {
constructor(@Inject(ElementRef) {nativeElement}: ElementRef<T>) {
super(nativeElement);
}
} ComponentFactoryResolver . , ngComponentOutlet? . — , Dependency Injection. ngComponentOutlet Injector, .
, , . . .
, . open-source- ng-polymorpheus. , , ngTemplateOutlet, ngContentOutlet . , ! .
. , . !