如何将组件选择器标记为弃用?

11

我有一个组件

@Component({
  // todo the app-old-selector selector must be removed in the next version
  selector: 'app-new-selector,app-old-selector',
  templateUrl: './component.html'
})
export class Component {
}

如何最好地通知开发人员 app-old-selector 已过时?


我知道现在已经太晚了,但是我写了一个可重用的装饰器来达到这个目的。请查看我的答案。 - dileepkumar jami
6个回答

8

我编写了一个可重复使用的装饰器,用于将组件的选择器标记为已弃用。

import {Component} from '@angular/core';

type Constructor<T = {}> = new (...args: any[]) => T;

export function Deprecated(oldSelector: string) { // This is a decorator factory
  return <T extends Constructor>(Base: T) => {
    return class Deprecated extends Base {
      selectors = [];
      constructor(...args: any[]) {
         super(...args);
         const selector = new Component((Deprecated as any).__annotations__[0]).selector;
         this.selectors = selector.split(', ');
         this.selectors = this.selectors.filter(selector => selector !== oldSelector);
         console.warn('The selector "' + oldSelector + '" is going to be deprecated. Please use one of these selectors [ ' + this.selectors.toString() + ' ]');
      }
    };
  };
}

现在我们只需要用以下参数的装饰器函数来修饰我们的组件类。
@Component({
  selector: 'my-old-app, my-app-new',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
@Deprecated("my-old-app")
export class AppComponent  {
  name = 'Angular';
}

请在stackblitz上找到代码链接
此外,请阅读我有关同一主题的博客文章,其中包含有关逻辑的说明。

这个想法真的很强大。然而,它不再兼容Angular v15+!我采纳了你的想法,并加以发挥。然而,对我来说如何构建新的类以获取选择器或使用Reflect做到这一点并不清楚,除了在这个例子中我是怎么做的: https://angular-deprecated-decorator-jgolrf.stackblitz.io - Michahell

7

你可能可以在组件代码内编写类似以下内容的代码:

import { Component, ElementRef } from '@angular/core'

@Component({
 selector: 'app-new-selector,app-old-selector',
 templateUrl: './component.html'
})
export class YourComponent {
    constructor(elem: ElementRef) {
        const tagName = elem.nativeElement.tagName.toLowerCase();
        if (tagName === 'app-old-selector') {
           console.warn('message');
        }
    }
}

这意味着我们只需将当前启动组件的标签名称与表示废弃值的字符串进行比较。如果它们相等-这意味着您现在需要通知开发人员。

这里有一个工作的Stackblitz示例,请随意打开控制台运行它。


静态检查怎么样? - constantant
1
你是什么意思? - Artem Arkhipov
1
我希望能像Typescript一样,在代码编写过程中帮助开发人员 :) - constantant
1
也许你可以尝试使用 JSDoc 的 @deprecated 属性进行支付。 http://usejsdoc.org/tags-deprecated.html - Artem Arkhipov

5
此外,你也可以简单地使用JSDoc的 @deprecated,像这样:
/**
* @deprecated write further comments here
*/
@Component({
  selector: 'component-name',
  templateUrl: './component-name.component.html',
  styleUrls: ['./component-name.component.scss']
})

这使类变为弃用状态,但不会对选择器产生任何影响。因此,您可能永远不会注意到该过时警告。 - btx

2

Angular 14.1+ 装饰器:

import { reflectComponentType } from '@angular/core';

/**
 * Deprecation decorator
 */
export function Deprecated(newSelector: string): ClassDecorator {
   return (target: any) => {
      const metadata = reflectComponentType(target);
      const selector = metadata.selector;
      console.error(`❌ The selector <${selector}> is deprecated. Use <${newSelector}> instead.`);
   }
}

可以用作:

@Component({
   selector: 'ui-preview-image',
})
@Deprecated('ui-new-preview')
export class PreviewImageComponent implements OnInit, OnChanges {

2
据我所知,没有内置的方法可以做到这一点。但是,您可以尝试使用ElementRef功能来提醒开发人员: "最初的回答"
import { Component, ElementRef } from '@angular/core'

@Component({
  selector: 'app-new-selector,app-old-selector',
  templateUrl: './component.html'
})
export class MyComponent {
  constructor(elem: ElementRef) {
    if (elem.nativeElement.tagName.toLowerCase() === 'app-old-selector') {
      console.warn(`'app-old-selector' selector is deprecated; use 'app-new-selector' instead.`);
    }
  }
}

或者,如果您需要使此功能可重用并希望确保库中的一致性,则可以创建一个可注入服务,如下所示:

最初的回答:

或者,如果你想让这个特性可以被重复使用,并且想要确保你的库的一致性,你可以创建一个可注入的服务,像这样:

import { Injectable } from '@angular/core';

@Injectable()
export class Deprecator {
  warnDeprecatedSelector(elem: ElementRef, oldSelector: string, newSelector: string) {
    if (elem.nativeElement.tagName.toLowerCase() === oldSelector) {
      console.warn(`'${oldSelector}' selector is deprecated; use '${newSelector}' instead.`);
    }
  }
}

import { Component, ElementRef } from '@angular/core'

@Component({
  selector: 'app-new-selector,app-old-selector',
  templateUrl: './component.html'
})
export class MyComponent {
  constructor(elem: ElementRef, deprecator: Deprecator) {
    deprecator.warnDeprecatedSelector(elem, 'app-old-selector', 'app-new-selector');
  }
}

但这种不可重用的方式不行,我需要每次都复制这段代码。 - Muhammed Albarmavi
如果您需要重复使用,可以将其转换为可注入的服务。 - Casey Rule

1
WebStorm的2023.1.3版本开始,IDE现在会对已弃用组件的使用进行删除线样式的显示。
/**
 * @deprecated DO NOT USE THIS TABLE.
 */
@Component({
  selector: 'app-table-old',
  templateUrl: './old-table.component.html',
  styleUrls: ['./old-table.component.scss']
})

现在在另一个组件模板中,我们使用了已弃用的组件,IDE将显示如下: 在Angular模板中使用已弃用的组件 注意:这似乎只在JSDoc注释放置在@Component注解之前时起作用。如果你把它放在后面(直接在export class OldTableComponent声明之前),删除线样式将不会被应用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接