英文:
Extending ngFor directive without the interface losing object typing
问题
在我们的应用程序中,每个对象都有与其关联的唯一ID。为了帮助呈现我们遇到的大型列表(其中有很多),我决定在我们的应用程序中的所有模板化的*ngFor
循环中使用trackby
函数。
我决定减少trackby
函数的重复,最佳方法是创建一个自定义的ngFor*
指令,如果发现所讨论的对象具有ID
或具有索引(业务逻辑决定这一点),则会自动添加自定义的trackby
。
这确实起作用,trackby
会像我希望的那样被添加。但是,当使用自定义的*ngFor
时,我注意到在模板中NgIterable对象的类型信息丢失了,而我不知道为什么,因为我在使用中进行了扩展。
以下是自定义指令的代码:
import {
Directive,
Input,
IterableDiffers,
NgIterable,
TemplateRef,
TrackByFunction,
ViewContainerRef,
} from "@angular/core";
import { NgFor, NgForOfContext } from "@angular/common";
import { InfiniteScrollItem } from "@shared/lists";
@Directive({
selector: "[dpsNgFor][[dpsNgForOf]]",
standalone: true,
})
export class DpsNgForDirective<T, U extends NgIterable<T> = NgIterable<T>> extends NgFor<T, U> {
public _trackBy(index: number, item: any) {
const _isScrollItem = (object: InfiniteScrollItem<T> | never) => "item" in object && "index" in object;
const _hasId = (object: InfiniteScrollItem<T> | never) => "id" in object;
// If it's an infinite scroll object, use the item.index;
if (_isScrollItem(item)) {
return item.index;
}
// Not an infinite scroll item
if (_hasId(item)) {
// Use the object id (if it has one).
return item.id;
}
// Fall back to index if id isn't found natively in the object.
return index;
}
@Input()
set dpsNgForOf(value) {
super.ngForOf = value;
}
@Input()
set dpsNgForTrackBy(trackBy: TrackByFunction<T>) {
super.ngForTrackBy = trackBy;
}
constructor(
public _viewContainer2: ViewContainerRef,
public _templateRef2: TemplateRef<NgForOfContext<T, U>>,
public _differs2: IterableDiffers
) {
super(_viewContainer2, _templateRef2, _differs2);
super.ngForTrackBy = this._trackBy;
}
}
将对象类型与接口的正确类型对应:
英文:
In our application, every object has a unique ID associated with it. To help with rendering of the large lists we occur (of which, there are many), I have decided to utilize trackby
functions for all templated *ngFor
loops within our app.
I decided the best course of action to reduce duplication of the trackby
functions, would be to create a custom ngFor*
directive that does this automatically, if it finds that the object in question has an ID
or has an index (business logic dictates this) it would add the custom trackby.
This does work, and the trackby gets added like I had hoped. However, when utilizing the custom *ngFor
I noticed that the typing gets lost on the NgIterable object within the template and I'm not sure why, since I am extending with usages.
Here is the custom directive:
import {
Directive,
Input,
IterableDiffers,
NgIterable,
TemplateRef,
TrackByFunction,
ViewContainerRef,
} from "@angular/core";
import { NgFor, NgForOfContext } from "@angular/common";
import { InfiniteScrollItem } from "@shared/lists";
@Directive({
selector: "[dpsNgFor][[dpsNgForOf]]",
standalone: true,
})
export class DpsNgForDirective<T, U extends NgIterable<T> = NgIterable<T>> extends NgFor<T, U> {
public _trackBy(index: number, item: any) {
const _isScrollItem = (object: InfiniteScrollItem<T> | never) => "item" in object && "index" in object;
const _hasId = (object: InfiniteScrollItem<T> | never) => "id" in object;
// If it's an infinite scroll object, use the item.index;
if (_isScrollItem(item)) {
return item.index;
}
// Not an infinite scroll item
if (_hasId(item)) {
// Use the object id (if it has one).
return item.id;
}
// Fall back to index if id isn't found natively in the object.
return index;
}
@Input()
set dpsNgForOf(value) {
super.ngForOf = value;
}
@Input()
set dpsNgForTrackBy(trackBy: TrackByFunction<T>) {
super.ngForTrackBy = trackBy;
}
constructor(
public _viewContainer2: ViewContainerRef,
public _templateRef2: TemplateRef<NgForOfContext<T, U>>,
public _differs2: IterableDiffers
) {
super(_viewContainer2, _templateRef2, _differs2);
super.ngForTrackBy = this._trackBy;
}
}
Any help would be appreciated, or pointed in the right direction.
Edit: Here are some examples of what I mean, when referring to "interface typing is lost".
This is what it typically looks like when the interface has the proper typing with a regular ngFor
And this is what it looks like with the custom ngFor directive. Both accomplish the goal of iterating correctly. This one just lost the typing associated with the object.
答案1
得分: 0
将代码翻译成中文:
原来,我必须在 `value` 变量上设置类型,以使其看起来像下面这样:
```typescript
@Input()
set dpsNgForOf(value: U & NgIterable<T>) {
super.ngForOf = value;
}
英文:
Turns out, I had to set typing on the value
variable so that it ended up looking like the following:
@Input()
set dpsNgForOf(value: U & NgIterable<T>) {
super.ngForOf = value;
}
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论