当前位置:网站首页>LayaBox - TypeScript - merge statement
LayaBox - TypeScript - merge statement
2022-08-02 10:11:00 【Gamla granite】
目录
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;
}️注意:Each set of statement sequence mouth remains the same,但各组接口之间的顺序是后来的接口重载出现在靠前位置.
这个规则有一个例外是当出现特殊的函数签名时. 如果签名里有一个参数的类型是 单一的字符串字面量(比如,不是字符串字面量的联合类型),那么它将会被提升到重载列表的最顶端.
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 { }
}合并规则与上面
合并命名空间In the section about rules,我们必须导出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 () {
// ...
}全局扩展与模块扩展的行为和限制是相同的.
边栏推荐
- qq邮箱日发5万邮件群发技术(qq邮箱怎样定时发送邮件)
- 周杰伦新歌发布,爬取《Mojito》MV弹幕,看看粉丝们都说的些啥!
- 斯皮尔曼相关系数
- 【New Edition】DeepFakes: Creation, Detection and Influence
- 牛客刷题——剑指offer(第三期)
- WPF 截图控件之文字(七)「仿微信」
- The 17th day of the special assault version of the sword offer
- R语言ggplot2可视化:使用ggpubr包的ggbarplot函数可视化水平柱状图(条形图)、使用orientation参数设置柱状图转置为条形图
- 使用较广泛的安全测试工具有哪些?
- 行为型模式-模板方法模式
猜你喜欢

Getting Started with SCM from Scratch (1): Summary of Background Knowledge

【New Edition】DeepFakes: Creation, Detection and Influence

第十五章 多线程

周杰伦新歌发布,爬取《Mojito》MV弹幕,看看粉丝们都说的些啥!

日元疲软令游戏机在日本变身“理财产品”:黄牛大赚

You Only Hypothesize Once: 用旋转等变描述子估计变换做点云配准(已开源)

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

迭代器失效问题

用正向迭代器封装实现反向迭代器

食品安全 | 鱼肝油不是鱼油,家有宝宝的注意了
随机推荐
你认同这个观点吗?大多数企业的数字化都只是为了缓解焦虑
Naive Bayesian Method of Li Hang's "Statistical Learning Methods" Notes
Facebook自动化数据分析方案,广告投放省心省力
你好,我的新名字叫“铜锁/Tongsuo”
从零开始入门单片机(一):必会背景知识总结
利用二维数据学习纹理三维网格生成(CVPR 2020)
软件测试H模型
R language ggplot2 visualization: use the ggbarplot function of the ggpubr package to visualize the horizontal column chart (bar chart), use the orientation parameter to set the column chart to be tra
要长续航还是更安全?海豹与深蓝SL03对比导购
关于缓存数据的探讨
R语言ggplot2可视化:使用ggpubr包的ggbarplot函数可视化堆叠的柱状图(stacked bar plot)、lab.pos参数指定柱状图的数值标签的位置,lab.col参数指定数值标
后管实现面包屑功能
DVWA 通关记录 2 - 命令注入 Command Injection
LayaBox---TypeScript---装饰器
Geoffery Hinton:深度学习的下一个大事件
软件测试的基本理论知识(软件测试面试基础知识)
软件测试X模型
R语言ggplot2可视化:基于aes函数中的fill参数和shape参数自定义绘制分组折线图并添加数据点(散点)、使用theme函数的legend.position函数配置图例到图像右侧
Linux系统卸载,安装,升级,迁移clickHouse数据库
如何搭建威纶通触摸屏与S7-200smart之间无线PPI通信?