当前位置:网站首页>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 () {
// ...
}全局扩展与模块扩展的行为和限制是相同的.
边栏推荐
猜你喜欢

WPF 截图控件之文字(七)「仿微信」

【New Edition】DeepFakes: Creation, Detection and Influence

周鸿祎称微软抄袭 360 安全模式后发文否认;英特尔CEO基辛格回应市值被AMD超越:股价下跌是咎由自取|极客头条...

牛客网项目2.7开发注册功能 报错This application has no explicit mapping for /error......

Rear tube implements breadcrumb function

【新版干货书】深度伪造 (DeepFakes):创造,检测和影响

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

李航《统计学习方法》笔记之感知机perceptron

matlab-day02

Facebook's automated data analysis solution saves worry and effort in advertising
随机推荐
Getting Started with SCM from Scratch (1): Summary of Background Knowledge
R语言ggplot2可视化:使用ggpubr包的ggbarplot函数可视化水平柱状图(条形图)、使用orientation参数设置柱状图转置为条形图
Rust 从入门到精通03-helloworld
Verilog's random number system task----$random
Linux系统卸载,安装,升级,迁移clickHouse数据库
npm ERR! 400 Bad Request - PUT xxx - Cannot publish over previously published version “1.0.0“.
刷题错题录1-隐式转换与精度丢失
关于缓存数据的探讨
21年毕业转行软件测试,从0收入到月薪过万,我真的很幸运...
第十五章 多线程
后管实现面包屑功能
软件工程国考总结——选择题
牛客网项目2.7开发注册功能 报错This application has no explicit mapping for /error......
要长续航还是更安全?海豹与深蓝SL03对比导购
一文带你了解推荐系统常用模型及框架
Smoothing of time series data in R language: smoothing time series data to remove noise using the dpill function and locpoly function of the KernSmooth package
程序员的浪漫七夕
斯皮尔曼相关系数
练习-17
yolov7创新点