TypeScript(十三)声明合并

本文最后更新于:9 个月前

目录

前言

同类型合并

接口合并

成员名相同

方法名相同

函数

命名空间

枚举

不同类型合并

类&接口

命名空间&枚举

命名空间&类

命名空间&函数

写在最后


前言

本文收录于TypeScript知识总结系列文章,欢迎指正!

相信读过上篇文章TS模块后,大家对TS的模块机制有了一定的了解,那么本篇文章将给大家介绍重名模块或者类型的声明合并以及使用方式

我们第一次接触到类似的概念是来源于函数这篇文章,其中函数的重载就是声明合并

声明合并指的是编译器会针对同名的声明合并为一个声明,合并后的声明会同时拥有原先两个或多个声明的特性,当两个或以上的变量、类型或者模块定义成同一个变量名时就会产生声明合并

TS中的声明合并包含接口,函数,命名空间,枚举,类之间的合并。接下来我会深入介绍这几种合并方式

同类型合并

接口合并

成员名相同

接口合并中接口的成员名可以重复,但类型必须相同

interface IAnimal {
   name: string
}

interface IAnimal {
   name: number // 后续属性声明必须属于同一类型。属性“name”的类型必须为“string”,但此处却为类型“number”
   color: string
}

const animal: IAnimal = {
   name: "阿黄",
   color: "black"
}

正确的写法应该是

// global.d.ts 
interface IAnimal {
    name: string
}
interface IAnimal {
    color: string
}

// 相当于
interface IAnimal {
    name: string
    color: string
}

// src/index.ts
const animal: IAnimal = {
    name: "阿黄",
    color: "black"
}

方法名相同

如果两个接口中出现相同的函数名,则按照函数的重载进行处理

// global.d.ts
interface IAnimal {
    getVal(val: number): number
}
interface IAnimal {
    getVal(val: string): string
}

// 相当于
interface IAnimal {
    getVal(val: number): number
    getVal(val: string): string
}

// src/index.ts
const animal: IAnimal = {
    getVal(val: any) {
       return val
    }
}

tips:箭头函数是不支持函数重载的,这点在写函数的文章时没提到,由于箭头函数是函数表达式,而不是函数声明,所以不支持函数的重载写法

函数

函数可以参考这篇文章

命名空间

我们回到模块这篇文章的那个问题:一个命名空间必须通过一处代码块定义吗?

我们在模块中提到了命名空间的实现实际上是使用一个iife(立即执行函数)对外部变量进行修改,达到封装的目的

// global.d.ts 
declare namespace global_type {
    interface IAnimal {
        name: string
        color: string
    }
}
declare namespace global_type {
    let animal: IAnimal
}

// 相当于
declare namespace global_type {
    interface IAnimal {
        name: string
        color: string
    }
    // let animal: IAnimal //使用let不能重复定义变量,这句会报错,所以先注释了
}

// src/index.ts
global_type.animal = {
    name: "",
    color: ""
}

名称相同的命名空间中的类型或者变量可以直接获取,比如上面代码中的IAnimal可以直接在命名空间取到。

枚举

枚举同样遵循合并规则,枚举中的key都是唯一值,所以不允许重复

// global.d.ts 
declare enum Position {
    x = 0
}
declare enum Position {
    y = 1
}
declare enum Position {
    z = 2
}
/*相当于
declare enum Position {
    x = 0,
    y = 1,
    z = 2
}*/

// src/index.ts
const { x, y, z } = Position

不同类型合并

类&接口

类和接口直接合并规则与接口直接合并相同

// global.d.ts
declare class Animal {
    name: string
}
declare interface Animal {
    age: number
}
declare let animal: Animal
// index.ts
animal = new class {
    name: string
    age: number
}

命名空间&枚举

命名空间与枚举同名时也会存在声明合并,结合之前说到的命名空间和枚举的实现原理不难理解,这二者合并实际上可以看成Position对象的合并

// global.d.ts 
declare enum Position {
    x = 0,
    y = 1,
    z = 2
}
declare namespace Position {
    const _x = Position.x
}
/*
可以看成
enum Position {
    x = 0,
    y = 1,
    z = 2,
    _x = Position.x
}*/
declare let x: Position.x
declare let y: Position.y

// src/index.ts
x = Position._x

命名空间&类

命名空间与类合并时,会在类上静态放置对应的属性。命名空间定义实际上是对上下文某个对象赋予属性,当命名空间与类相遇,可以看成是添加了类的static属性

class Animal {
    age: number
}
namespace Animal {
    export let age: number = 10
}
console.log(Animal);// [class Animal] { age: 10 }
const animal = new Animal()
animal.age = Animal.age

tips:命名空间声明不能位于与之合并的类或函数前

命名空间&函数

函数和类类似,都是添加自身静态属性

function Animal() {
    return Animal.age// 取自身的age属性
}
namespace Animal {
    export let age: number = 10
}

console.log(Animal);// [Function: Animal] { age: 10 }
const age = Animal()
console.log(age);// 10

写在最后

以上就是文章全部内容,文章主要带领大家了解了TS中的相同类型以及不同类型的合并,其中包括函数,命名空间,枚举,类以及接口之间的合并关系

感谢你看到了最后,如果觉得文章不错的话,还望三连支持一下,谢谢!

相关文章

声明合并 · TypeScript 入门教程

声明合并 - TypeScript 中文手册