We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
对于初学Typescript的同学来说,声明文件一定是一个让人十分头疼、但是怎么也绕不开的问题。声明文件的书写和声明合并在Typescript官方文档里面已经有比较详细的介绍,这里不再陈述。我们重点讨论的是如何扩展第三方模块中的类型。
类型扩展的基本原则 如何扩展第三方模块中的类型,有三条基本原则:
同模块:声明合并只能在同一个模块中进行 同路径:声明的模块路径必须与目标类型(你将要扩展的类型)的原始声明文件路径保持一致 同书写方式:声明书写方式必须与目标类型一致 下面来详细展开
原则一:同模块 声明合并只能在同一个模块中进行。意思是说,在扩展一个类型之前,你需要先引入这个类型所在的模块。
在下面这个例子中,我们需要为接口Foo扩展一个属性Bar,Foo是在moduleOfFoo中声明的,为此我们需要先引入moduleOfFoo:
// 引入`Foo`所在的模块`moduleOfFoo`,这一步非常重要 import 'moduleOfFoo'
然后我们需要声明一个同名的模块,在模块内部进行Foo的声明合并
// 引入`Foo`所在的模块`moduleOfFoo`,这一步非常重要 import 'moduleOfFoo' // 声明同名模块 declare module 'moduleOfFoo' { // 在这个空间内才可以进行声明合并 interface Foo { Bar: any } }
原则二:同路径 声明的模块路径必须与目标类型(你将要扩展的类型)的原始声明文件路径保持一致。 我们来看一个例子: 首先我们在a.d.ts中声明了interface A
// a.d.ts export declare interface A { a: number }
b.d.ts引用了A然后导出
// b.d.ts export { A } from './a'
现在我们来扩展interface A
import './b' declare module './a' { interface A { test: number } }
注意这里declare module './a',因为interface A就是在'./a'中定义的,必须在这个模块中才能够合并声明。 顺便说一下,这里的import './b',改成import './a'也是可以的,因为都能达到引入interface A的目的。唯有declare module './a'不可以改成declare module './b',因为'./b'不是interface A的原始声明文件。
原则三:同书写方式 声明书写方式必须与目标类型一致。这里主要是说namespace嵌套关系要保持一致。 在下面这个例子中我们将要为joint.dia.CellView扩展两个方法getData和setData。 通过观察joint.d.ts,我们得知CellView嵌套了两层namespace:
export namespace dia { // ... export namespace CellView { // ... } // ... }
所以我们在合并声明的时候,也需要嵌套两层同样的namespace
// 扩展jointjs import jointjs from 'jointjs' declare module 'jointjs' { namespace dia { interface CellView { getData: (key?: string) => any setData: (data: any, value?: any) => void } } }
Typescript声明合并的规则在官方文档有详细的解释,大家感兴趣可以去看看。需要注意的是:
声明合并无法覆盖原有的类型 类不能与其它类或变量合并
// a.d.ts export declare interface A { a: number b: number } export declare let B: number export declare class C { a: number }
我们希望将A.a和B的类型改为string,直接覆盖声明是无效的:
// custom.d.ts import './a' declare module './a' { // 直接覆盖属性a无效 interface A { a: string } // 直接覆盖类型B无效 let B: string }
如果你实在需要覆盖A.a的类型,可以考虑使用继承:
// code.ts // 这里不是声明文件,是实实在在的ts代码 import { A as _A } from './a' export interface A extends _A { a: string }
当然这里也并没有覆盖A.a的类型,不过你可以使用这个新的code.ts中的interface A。
现在我们需要扩展class C的实例属性和静态属性,直接用class覆盖是无效的
// custom.d.ts import './a' declare module './a' { // 直接覆盖class无效 class C { b: number static c: number } }
我们可以用interface来扩展class的实例属性,用namespace来扩展class的静态属性:
// custom.d.ts import './a' declare module './a' { // 使用interface扩展class的实例属性 interface C { b: number } // 使用namespace扩展class的静态属性 namespace C { let c: number } }
如果你在扩展第三方类型的时候遇到问题,请参考以上这三条原则,相信你能够找到答案~
转 Typescript声明文件-第三方类型扩展
The text was updated successfully, but these errors were encountered:
No branches or pull requests
对于初学Typescript的同学来说,声明文件一定是一个让人十分头疼、但是怎么也绕不开的问题。声明文件的书写和声明合并在Typescript官方文档里面已经有比较详细的介绍,这里不再陈述。我们重点讨论的是如何扩展第三方模块中的类型。
类型扩展的基本原则
如何扩展第三方模块中的类型,有三条基本原则:
同模块:声明合并只能在同一个模块中进行
同路径:声明的模块路径必须与目标类型(你将要扩展的类型)的原始声明文件路径保持一致
同书写方式:声明书写方式必须与目标类型一致
下面来详细展开
原则一:同模块
声明合并只能在同一个模块中进行。意思是说,在扩展一个类型之前,你需要先引入这个类型所在的模块。
在下面这个例子中,我们需要为接口Foo扩展一个属性Bar,Foo是在moduleOfFoo中声明的,为此我们需要先引入moduleOfFoo:
然后我们需要声明一个同名的模块,在模块内部进行Foo的声明合并
原则二:同路径
声明的模块路径必须与目标类型(你将要扩展的类型)的原始声明文件路径保持一致。
我们来看一个例子:
首先我们在a.d.ts中声明了interface A
b.d.ts引用了A然后导出
现在我们来扩展interface A
注意这里declare module './a',因为interface A就是在'./a'中定义的,必须在这个模块中才能够合并声明。
顺便说一下,这里的import './b',改成import './a'也是可以的,因为都能达到引入interface A的目的。唯有declare module './a'不可以改成declare module './b',因为'./b'不是interface A的原始声明文件。
原则三:同书写方式
声明书写方式必须与目标类型一致。这里主要是说namespace嵌套关系要保持一致。
在下面这个例子中我们将要为joint.dia.CellView扩展两个方法getData和setData。
通过观察joint.d.ts,我们得知CellView嵌套了两层namespace:
所以我们在合并声明的时候,也需要嵌套两层同样的namespace
Typescript声明合并的规则在官方文档有详细的解释,大家感兴趣可以去看看。需要注意的是:
声明合并无法覆盖原有的类型
类不能与其它类或变量合并
我们希望将A.a和B的类型改为string,直接覆盖声明是无效的:
如果你实在需要覆盖A.a的类型,可以考虑使用继承:
当然这里也并没有覆盖A.a的类型,不过你可以使用这个新的code.ts中的interface A。
现在我们需要扩展class C的实例属性和静态属性,直接用class覆盖是无效的
我们可以用interface来扩展class的实例属性,用namespace来扩展class的静态属性:
如果你在扩展第三方类型的时候遇到问题,请参考以上这三条原则,相信你能够找到答案~
转 Typescript声明文件-第三方类型扩展
The text was updated successfully, but these errors were encountered: