Можно ли использовать сигнал computed для ввода Guard в шаблоне? Я использую Angular 17.0.0 (17.1.0 требуется для сигналов input, которые мы не можем изменить для этой версии библиотеки).
У меня есть два теста внутри этого компонента: один с использованием сигнала isItem и один с использованием функции isItemFn.
isItem кажется, не позволяет мне печатать this.item.isItemFn позволяет мне печатать this.item.Поскольку значение item может быть одним из трех (подробнее об этом позже), мне нужен способ применить защиту типа в шаблоне, и я надеялся, что сигналы помогут, но пока этого не произошло. Есть ли способ сделать это без использования функции или канала?
@Component({})
export class CompositeChipsDisplayComponent<T> {
@Input() item!: T;
// Doesn't allow for type guards in the template
isItem = computed(() => this.item instanceof CompositeChipsItemDirective);
// Does allow for type guards in the template (but runs too often)
isItemFn(item: unknown): item is CompositeChipsItemDirective {
return item instanceof CompositeChipsItemDirective;
}
}
<!-- Types work within the `if` statement when using a function -->
@if (isItemFn(item)) {
<button class = "item">
{{ item.label }}
</button>
}
<!-- Types do not work within the `if` statement when using a signal -->
@if (isItem()) {
<button class = "item">
{{ item.label }}
</button>
}
Вот как выглядит результат в моем редакторе:
Наверное, я никогда об этом не думал, есть идеи получше? У меня нет доступа к 17.1.x для сигналов input. Трубы — мой единственный вариант здесь?





Проблемы с вашим кодом следующие.
Вы используете instanceof CompositeChipsItemDirective, который преобразует вычисленное значение в сигнал boolean, вместо этого вам следует просто вернуть сигнал после приведения его к типу директивы.
Вы используете вычисление в HTML, но снова используете исходный ввод внутри шаблона, обращаясь к метке. Вместо этого используйте синтаксис @if as и тип, полученный из вычисленного сигнала, и все должно работать нормально.
import { Component, computed, Directive, Input, Signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
@Directive({
selector: '[someDirective]',
standalone: true,
exportAs: 'someDirective',
})
export class CompositeChipsItemDirective {
label = 'test';
}
@Component({
selector: 'app-child',
standalone: true,
template: `
@if (isItemFn(item)) {
<button class = "item">
{{ item.label }}
</button>
}
@if (isItem(); as itemCasted) {
<button class = "item">
{{ itemCasted.label }}
</button>
}
`,
})
export class CompositeChipsDisplayComponent<T> {
@Input() item!: T;
// Doesn't allow for type guards in the template
isItem: Signal<CompositeChipsItemDirective> = computed(
() => return this.item instanceof CompositeChipsItemDirective ? this.item as CompositeChipsItemDirective : null;
);
// Does allow for type guards in the template (but runs too often)
isItemFn(item: unknown): item is CompositeChipsItemDirective {
return item instanceof CompositeChipsItemDirective;
}
}
@Component({
selector: 'app-root',
standalone: true,
imports: [CompositeChipsDisplayComponent, CompositeChipsItemDirective],
template: `
<app-child [item] = "test"/>
<div #test = "someDirective" someDirective></div>
`,
})
export class App {
name = 'Angular';
}
bootstrapApplication(App);
@if всегда будет возвращать истину, и поскольку у меня есть три разных элемента, он потерпит неудачу, если тип не относится к этому типу. (CompositeChipsItemDirective, CompositeChipsDateDirective, CompositeChipsRangeDirective)
хотя возврат return this.item instanceof CompositeChipsItemDirective ? this.item : null; работает
@GetOffMyLawn извините, не понял эту часть требования, обновил свой ответ, добавив тот же приятный улов!
this.itemне является сигналом. Почему вы вообще используете компьютерный сигнал? Он никогда не будет обновляться после инициализации. Если бы это был входной сигнал , это имело бы больше смысла.