ngOnChanges 挂钩中 SimpleChanges 接口的类型检查

Posted

技术标签:

【中文标题】ngOnChanges 挂钩中 SimpleChanges 接口的类型检查【英文标题】:Type checking for SimpleChanges interface in ngOnChanges hook 【发布时间】:2017-10-24 23:38:33 【问题描述】:

如果我们在当前组件的 ngOnChanges 钩子的 SimpleChanges typescript 参数中进行类型检查,那就太好了。

这将防止我们检查的属性出现错误。

【问题讨论】:

【参考方案1】:

使用 TypeScript 2.1keyof 功能,我发现了以下类型声明(基于 SimpleChanges),这似乎为我们提供了对组件属性的必要类型化访问:

export type ComponentChange<T, P extends keyof T> = 
    previousValue: T[P];
    currentValue: T[P];
    firstChange: boolean;
;

export type ComponentChanges<T> = 
    [P in keyof T]?: ComponentChange<T, P>;
;

使用这些,声明 vscode 编辑器自动获取类型信息并自动完成更改属性:

一个问题是 changes 参数现在将列出组件的每个属性(不仅是 @Input() 属性),但我还没有找到比这更好的方法这个。

【讨论】:

使用继承,即使您可以迭代所有输入,但并非所有输入都可能发生变化。扩展 Simple Changes 接口将明确组件期望更改的输入。反正只是我的 2 美分。【参考方案2】:

我使用继承解决了这个问题。首先,我创建了扩展 SimpleChange 类的类型化接口。您只需要执行一次并将其导入需要它的组件中。

interface TypedChange<T> extends SimpleChange

    previousValue: T;
    currentValue: T;

其次,我们将 SimpleChanges 接口扩展为预期会在我们的组件中更改的接口。例如

interface MyComponentChanges extends SimpleChanges

    RefreshQueue: TypedChange<number>

最后的实现是

public ngOnChanges(changes: MyComponentChanges): void

    if (changes.RefreshQueue)
    
        if (!changes.RefreshQueue.isFirstChange())
        
            if (changes.RefreshQueue.currentValue == 1)
            
                DoSomething();
            
        
    

下面的智能感知屏幕截图

【讨论】:

【参考方案3】:

我建议以下解决方案,改编自https://github.com/angular/angular/issues/17560#issuecomment-624161007

export type SimpleChangeTyped<T> = Omit<SimpleChange, SimpleChange['previousValue'] | SimpleChange['currentValue']>
  & 
    previousValue: T;
    currentValue: T;
  ;

export type SimpleChangesTyped<T> = 
  [K in keyof T]: SimpleChangeTyped<T[K]>;
;

此方案具有以下优点:

完全输入/与智能感知一起使用 不会覆盖/联合在 SimpleChange 上固有的属性 适用于this 防止不良属性 如果 Angular 开发人员决定更改 SimpleChange 上的 previousValuecurrentValue 属性,将引发错误

用法示例:

ngOnChanges(changes: SimpleChangesTyped<YourComponent>): void  // Or use SimpleChangesTyped<this>
    changes.someComponentProperty; // GOOD: Will identify the changes object with correct types
    changes.someOtherProperty; // BAD: Property 'someOtherProperty' does not exist on type 'SimpleChangesTyped<YourComponent>'.ts(2339)
    changes.someComponentProperty.currentValue; // GOOD: Will identify the type of the someComponentProperty property
    changes.someComponentProperty.firstChange; // GOOD: Will identify the type of the SimpleChange firstChange property (boolean)
    changes.someComponentProperty.someOtherProperty; // BAD: Property 'someOtherProperty' does not exist on type 'SimpleChangeTyped<SomeComponentPropertyType>'.ts(2339)
  

此方法的唯一缺点是它不继承/合并 SimpleChanges,因此如果将来向此接口添加任何属性,它们对 SimpleChangesTyped 无效。我尝试使用以下变体:

export type SimpleChangesTyped<T> =
  Omit<SimpleChanges, keyof T> &
  
    [K in keyof T]: SimpleChangeTyped<T[K]>;
  ;

但遗憾的是,这不起作用,因为您最终再次允许所有键。

【讨论】:

【参考方案4】:

有来自 Netanel Basal 的a solution

type MarkFunctionPropertyNames<T> = 
  [Key in keyof T]: T[Key] extends Function | Subject<any> ? never : Key;

type ExcludeFunctionPropertyNames<T extends object> = MarkFunctionPropertyNames<T>[keyof T];
type ExcludeFunctions<T extends object> = Pick<T, ExcludeFunctionPropertyNames<T>>;
export type NgChanges<TComponent extends object, TProps = ExcludeFunctions<TComponent>> = 
  [Key in keyof TProps]: 
    previousValue: TProps[Key];
    currentValue: TProps[Key];
    firstChange: boolean;
    isFirstChange(): boolean;
  

// ...
@Component(...)
export class MyComponent 
  ngOnChanges(changes: NgChanges<MyComponent>)  

【讨论】:

请注意,使用此单元测试可能会 need to be modified 到 const changes: NgChanges&lt;MyComponent&gt; = as any; changes.something = new SimpleChange(null, someData, true); component.ngOnChanges(changes);

以上是关于ngOnChanges 挂钩中 SimpleChanges 接口的类型检查的主要内容,如果未能解决你的问题,请参考以下文章

Angular Lifecycle Interface OnChanges 应该为方法 ngOnChanges 实现

ngOnchanges 和 DoCheck 角度

如何停止在 ngOnInit() 之前调用的 ngOnChanges

从 Angular 中的 @Input 更新 ngOnChanges 视图

为啥 Angular 2 ngOnChanges 不响应输入数组推送

ngOnChanges 在 Angular4 中不起作用