当前位置:网站首页>LayaBox---TypeScript---声明合并
LayaBox---TypeScript---声明合并
2022-08-02 10:01:00 【格拉格拉】
目录
1.介绍
TypeScript中有些独特的概念可以在类型层面上描述JavaScript对象的模型。 这其中尤其独特的一个例子是“声明合并”的概念。 理解了这个概念,将有助于操作现有的JavaScript代码。 同时,也会有助于理解更多高级抽象的概念。
对本文件来讲,“声明合并”是指编译器将针对同一个名字的两个独立声明合并为单一声明。 合并后的声明同时拥有原先两个声明的特性。 任何数量的声明都可被合并;不局限于两个声明。
2.基础概念
TypeScript中的声明会创建以下三种实体之一:命名空间、类型 或 值。
创建命名空间的声明会新建一个命名空间,它包含了用(.)符号来访问时使用的名字。 创建类型的声明是:用声明的模型创建一个类型并绑定到给定的名字上。 最后,创建值的声明会创建在JavaScript输出中看到的值。
| Declaration | Namespace | Type | Value |
| Namespace | X | X | |
| Class | X | X | |
| Enum | X | X | |
| Interface | X | ||
| Type Alias | X | ||
| Function | X | ||
| Variable | X |
理解每个声明创建了什么,有助于理解当声明合并时有哪些东西被合并了。
3.合并接口
最简单也最常见的声明合并类型是接口合并。
interface Box {
height: number;
width: number;
}
interface Box {
scale: number;
}
let box: Box = {height: 5, width: 6, scale: 10};接口的非函数的成员应该是唯一的。
如果它们不是唯一的,那么它们必须是相同的类型。
如果两个接口中同时声明了同名的非函数成员且它们的类型不同,则编译器会报错。
对于函数成员,每个同名函数声明都会被当成这个函数的一个重载。 同时需要注意,当接口 A与后来的接口 A合并时,后面的接口具有更高的优先级。
interface Cloner {
clone(animal: Animal): Animal;
}
interface Cloner {
clone(animal: Sheep): Sheep;
}
interface Cloner {
clone(animal: Dog): Dog;
clone(animal: Cat): Cat;
}这三个接口合并成一个声明:
interface Cloner {
clone(animal: Dog): Dog;
clone(animal: Cat): Cat;
clone(animal: Sheep): Sheep;
clone(animal: Animal): Animal;
}️注意:每组接口里的声明顺序保持不变,但各组接口之间的顺序是后来的接口重载出现在靠前位置。
这个规则有一个例外是当出现特殊的函数签名时。 如果签名里有一个参数的类型是 单一的字符串字面量(比如,不是字符串字面量的联合类型),那么它将会被提升到重载列表的最顶端。
interface Document {
createElement(tagName: any): Element;
}
interface Document {
createElement(tagName: "div"): HTMLDivElement;
createElement(tagName: "span"): HTMLSpanElement;
}
interface Document {
createElement(tagName: string): HTMLElement;
createElement(tagName: "canvas"): HTMLCanvasElement;
}合并后的 Document将会像下面这样:
interface Document {
createElement(tagName: "canvas"): HTMLCanvasElement;
createElement(tagName: "div"): HTMLDivElement;
createElement(tagName: "span"): HTMLSpanElement;
createElement(tagName: string): HTMLElement;
createElement(tagName: any): Element;
}4.合并命名空间
同名的命名空间也会合并其成员。 命名空间会创建出命名空间和值,我们需要知道这两者都是怎么合并的。
对于命名空间的合并,模块导出的同名接口进行合并,构成单一命名空间内含合并后的接口。
对于命名空间里值的合并,如果当前已经存在给定名字的命名空间,那么后来的命名空间的导出成员会被加到已经存在的那个模块里。
Animals声明合并示例:
namespace Animals {
export class Zebra { }
}
namespace Animals {
export interface Legged { numberOfLegs: number; }
export class Dog { }
}
等同于:
namespace Animals {
export interface Legged { numberOfLegs: number; }
export class Zebra { }
export class Dog { }
}下例提供了更清晰的说明:
namespace Animal {
let haveMuscles = true;
export function animalsHaveMuscles() {
return haveMuscles;
}
}
namespace Animal {
export function doAnimalsHaveMuscles() {
// Error, because haveMuscles is not accessible here
return haveMuscles;
}
}因为 haveMuscles并没有导出,只有 animalsHaveMuscles函数共享了原始未合并的命名空间可以访问这个变量。 doAnimalsHaveMuscles函数虽是合并命名空间的一部分,但是访问不了未导出的成员。
5.命名空间与类和函数和枚举类型合并
命名空间可以与其它类型的声明进行合并。 只要命名空间的定义符合将要合并类型的定义。合并结果包含两者的声明类型。
5.1 合并命名空间和类
--这让我们可以表示内部类。
class Album {
label: Album.AlbumLabel;
}
namespace Album {
export class AlbumLabel { }
}合并规则与上面
合并命名空间小节里讲的规则一致,我们必须导出AlbumLabel类,好让合并的类能访问。 合并结果是一个类并带有一个内部类。 你也可以使用命名空间为类增加一些静态属性。
除了内部类的模式,你在JavaScript里,创建一个函数稍后扩展它增加一些属性也是很常见的。 TypeScript使用声明合并来达到这个目的并保证类型安全。
function buildLabel(name: string): string {
return buildLabel.prefix + name + buildLabel.suffix;
}
namespace buildLabel {
export let suffix = "";
export let prefix = "Hello, ";
}
console.log(buildLabel("Sam Smith"));相似的,命名空间可以用来扩展枚举型:
enum Color {
red = 1,
green = 2,
blue = 4
}
namespace Color {
export function mixColor(colorName: string) {
if (colorName == "yellow") {
return Color.red + Color.green;
}
else if (colorName == "white") {
return Color.red + Color.green + Color.blue;
}
else if (colorName == "magenta") {
return Color.red + Color.blue;
}
else if (colorName == "cyan") {
return Color.green + Color.blue;
}
}
}6.非法的合并
TypeScript并非允许所有的合并。 目前,类不能与其它类或变量合并。
7.模块扩展
虽然JavaScript不支持合并,但你可以为导入的对象打补丁以更新它们。
// observable.js
export class Observable<T> {
// ... implementation left as an exercise for the reader ...
}
// map.js
import { Observable } from "./observable";
Observable.prototype.map = function (f) {
// ... another exercise for the reader
}它也可以很好地工作在TypeScript中, 但编译器对 Observable.prototype.map一无所知。 你可以使用扩展模块来将它告诉编译器:
// observable.ts stays the same
// map.ts
import { Observable } from "./observable";
declare module "./observable" {
interface Observable<T> {
map<U>(f: (x: T) => U): Observable<U>;
}
}
Observable.prototype.map = function (f) {
// ... another exercise for the reader
}
// consumer.ts
import { Observable } from "./observable";
import "./map";
let o: Observable<number>;
o.map(x => x.toFixed());模块名的解析和用
import/export解析模块标识符的方式是一致的。 当这些声明在扩展中合并时,就好像在原始位置被声明了一样。 但是,你不能在扩展中声明新的顶级声明-仅可以扩展模块中已经存在的声明。
8.全局扩展
你也以在模块内部添加声明到全局作用域中。
// observable.ts
export class Observable<T> {
// ... still no implementation ...
}
declare global {
interface Array<T> {
toObservable(): Observable<T>;
}
}
Array.prototype.toObservable = function () {
// ...
}全局扩展与模块扩展的行为和限制是相同的。
边栏推荐
- logo 图标(php图片加文字水印)
- 软件测试之发现和解决bug
- 云原生应用平台的核心模块有哪些
- 【OpenCV】-霍夫变换
- typeinfo类型支持库学习
- R语言时间序列数据的平滑:使用KernSmooth包的dpill函数和locpoly函数对时间序列数据进行平滑以消除噪声
- php组件漏洞
- 李航《统计学习方法》笔记之监督学习Supervised learning
- The R language uses the ggtexttable function of the ggpubr package to visualize the table data (draw the table directly or add the table data to the image), set the theme parameter to customize the fi
- 【技术分享】OSPFv3基本原理
猜你喜欢

第十五章 多线程

Naive Bayesian Method of Li Hang's "Statistical Learning Methods" Notes

The realization of the list

npm ERR! 400 Bad Request - PUT xxx - Cannot publish over previously published version “1.0.0“.

Rear tube implements breadcrumb function

转转反爬攻防战

Verilog的随机数系统任务----$random

使用scrapy 把爬到的数据保存到mysql 防止重复

软件测试H模型

8月份的.NET Conf 活动 专注于 .NET MAUI
随机推荐
Do you agree with this view?Most businesses are digitizing just to ease anxiety
练习16-两道模拟题
刷题错题录1-隐式转换与精度丢失
The R language uses the ggtexttable function of the ggpubr package to visualize the table data (draw the table directly or add the table data to the image), set the theme parameter to customize the fi
The R language uses the rollapply function in the zoo package to apply the specified function to the time series in a rolling manner and the window moves, and set the align parameter to specify that t
The perceptron perceptron of Li Hang's "Statistical Learning Methods" notes
日元疲软令游戏机在日本变身“理财产品”:黄牛大赚
Using the TCP protocol, will there be no packet loss?
【OpenCV】-霍夫变换
后管实现面包屑功能
第15章 泛型
你好,我的新名字叫“铜锁/Tongsuo”
R language ggplot2 visualization: use the ggbarplot function of the ggpubr package to visualize the stacked bar plot, the lab.pos parameter specifies the position of the numerical label of the bar cha
Mistakes in Brushing the Questions 1-Implicit Conversion and Loss of Precision
软件测试X模型
Facebook's automated data analysis solution saves worry and effort in advertising
李航《统计学习方法》笔记之朴素贝叶斯法
Implementation of mysql connection pool
适配器模式适配出栈和队列及优先级队列
要长续航还是更安全?海豹与深蓝SL03对比导购