找回密码
 立即注册
首页 业界区 安全 TypeScript Declaration Merging(声明合并)使用说明 ...

TypeScript Declaration Merging(声明合并)使用说明

高清宁 前天 13:00
最近在进行前端开发的时候,为了拓展引用,使用了TS声明合并的特性,完整的了解了一下该特性,特此记录成笔记。

声明合并指在TypeScript里面,编译器将两个或者多个独立的相同名称的声明合并到一起。合并后的定义同时包含所有声明。可以理解为声明的拓展
接口合并

最常见的合并就是接口合并,接口合并后的成员会整合到一起。


  • 接口中的非函数成员应该是唯一的,如果不是唯一,那他们必须有相同的类型,如果声明了两个同名但是类型不通的非函数成员会报错
  • 对于函数成员而言,每一个同名函数成员都相当于当前函数成员的一个版本,第一个接口A和第二个接口A合并的时候,第二个接口声明对象的优先级会高于第一个
eg:
  1. interface Cloner {
  2.   clone(animal: Animal): Animal;
  3. }
  4. interface Cloner {
  5.   clone(animal: Sheep): Sheep;
  6. }
  7. interface Cloner {
  8.   clone(animal: Dog): Dog;
  9.   clone(animal: Cat): Cat;
  10. }
复制代码
合并后:
  1. interface Cloner {
  2.   clone(animal: Dog): Dog;
  3.   clone(animal: Cat): Cat;
  4.   clone(animal: Sheep): Sheep;
  5.   clone(animal: Animal): Animal;
  6. }
复制代码

  • 当函数参数是单个字符串字面量类型时,合并后将被“提升”至重载列表顶部
eg:
  1. interface Document {
  2.   createElement(tagName: any): Element;
  3. }
  4. interface Document {
  5.   createElement(tagName: "div"): HTMLDivElement;
  6.   createElement(tagName: "span"): HTMLSpanElement;
  7. }
  8. interface Document {
  9.   createElement(tagName: string): HTMLElement;
  10.   createElement(tagName: "canvas"): HTMLCanvasElement;
  11. }
复制代码
合并后:
  1. interface Document {
  2.   createElement(tagName: "canvas"): HTMLCanvasElement;
  3.   createElement(tagName: "div"): HTMLDivElement;
  4.   createElement(tagName: "span"): HTMLSpanElement;
  5.   createElement(tagName: string): HTMLElement;
  6.   createElement(tagName: any): Element;
  7. }
复制代码
合并命名控件

和接口合并类似,合并命名空间的时候也会合并其成员


  • 合并命名空间的时候,每个命名空间中声明的导出接口的类型定义会自行进行合并,从而形成一个包含合并后的接口定义的单一命名空间。未导出的类型不会合并
eg:
  1. namespace Animals {
  2.   export class Zebra {}
  3. }
  4. namespace Animals {
  5.   export interface Legged {
  6.     numberOfLegs: number;
  7.   }
  8.   export class Dog {}
  9. }
复制代码
合并后:
  1. namespace Animals {
  2.   export interface Legged {
  3.     numberOfLegs: number;
  4.   }
  5.   export class Zebra {}
  6.   export class Dog {}
  7. }
复制代码
模块扩充

虽然 JavaScript 模块不支持合并操作,但可以通过导入并更新现有对象来对其进行修补,在使用第三方框架,框架引用了其他组件,但是第三方框架没有提供该组件足够的属性的时候,可以使用这种方式来拓展来避免更新整个框架。

eg:
  1. // observable.ts
  2. export class Observable<T> {
  3.   // ... implementation left as an exercise for the reader ...
  4. }
  5. // map.ts
  6. import { Observable } from "./observable";
  7. declare module "./observable" {
  8.   interface Observable<T> {
  9.     map<U>(f: (x: T) => U): Observable<U>;
  10.   }
  11. }
  12. Observable.prototype.map = function (f) {
  13.   // ... another exercise for the reader
  14. };
  15. // consumer.ts
  16. //通过拓展合并来使用户来调用Observable的map方法
  17. import { Observable } from "./observable";
  18. import "./map";
  19. let o: Observable<number>;
  20. o.map((x) => x.toFixed());
复制代码
eg2;
原本的框架里面,对
  1. export declare const Table: {
  2.         tooltipOptions: import("vue").PropType<Partial<Pick<import("element-plus").ElTooltipProps, "showArrow" | "appendTo" | "transition" | "effect" | "enterable" | "popperClass" | "offset" | "placement" | "popperOptions" | "showAfter" | "hideAfter">>>;
  3.         }
  4. export default Table;
  5. export type {TableProps}
复制代码
这里Table是某框架封装的属性,使用了的element-plus组件,并提供了tooltipOptions部分属性,但是这里是不够的,实际使用的时候期望可以使用全部属性,又不想升级框架,这里就可以声明命名空间来进行拓展。
  1. // src/types/pure-table.d.ts
  2. import "element-plus";
  3. import "/table";
  4. // 声明合并 TableProps
  5. declare module "/table" {
  6.   // 这里扩展 PureTableProps 的定义
  7.   interface PureTableProps {
  8.     // 扩展 tooltipOptions 支持完整的 ElTooltipProps
  9.     tooltipOptions?: Partial<import("element-plus").ElTooltipProps>;
  10.   }
  11. }
复制代码
合并之后,在使用Tabel组件的时候,其提供的tooltipOptions属性将支持完整的ElTooltipProps
命名空间与类、函数、枚举合并

目前Ts支持命名空间与其他类型的合并,需要注意的是类与类之间的合并是不允许的

命名空间和类
  1. class Album {
  2.   label: Album.AlbumLabel;
  3. }
  4. namespace Album {
  5.   export class AlbumLabel {}
  6. }
复制代码
此时Album.label是合法的调用
命名空间和函数
  1. function buildLabel(name: string): string {
  2.   return buildLabel.prefix + name + buildLabel.suffix;
  3. }
  4. namespace buildLabel {
  5.   export let suffix = "";
  6.   export let prefix = "Hello, ";
  7. }
  8. console.log(buildLabel("Sam Smith"));
复制代码
命名空间和枚举
  1. enum Color {
  2.   red = 1,
  3.   green = 2,
  4.   blue = 4,
  5. }
  6. namespace Color {
  7.   export function mixColor(colorName: string) {
  8.     if (colorName == "yellow") {
  9.       return Color.red + Color.green;
  10.     } else if (colorName == "white") {
  11.       return Color.red + Color.green + Color.blue;
  12.     } else if (colorName == "magenta") {
  13.       return Color.red + Color.blue;
  14.     } else if (colorName == "cyan") {
  15.       return Color.green + Color.blue;
  16.     }
  17.   }
  18. }
复制代码
More info: Learnerping的个人微博

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册