在ngOnChanges钩子中键入检查SimpleChanges接口

时间:2017-05-24 14:36:39

标签: angular visual-studio-code lifecycle typescript2.1 ngonchanges

如果我们在当前Component的ngOnChanges钩子的SimpleChanges typescript参数中进行类型检查会很棒。

这可以防止我们检查属性中的错误。

4 个答案:

答案 0 :(得分:3)

使用 TypeScript 2.1 keyof 功能,我已经找到了以下类型声明(基于SimpleChanges),这似乎为我们提供了对Component属性的必要类型访问:

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编辑器会自动获取类型信息并自动完成更改属性:

enter image description here

但有一个问题是更改参数现在将列出组件的每个属性(而不仅仅是@Input()属性)但我还没有找到比此

答案 1 :(得分:1)

我使用继承解决了这个问题。首先,我创建了扩展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();
            }
        }
    }
}

智能感知屏幕截图

enter image description here

答案 2 :(得分:0)

我建议根据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
  • 防止不良财产的行为
  • 如果有角度的开发人员决定更改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]>;
  };

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

答案 3 :(得分:0)

有来自 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>) { }
}