美文网首页
如何编写.d.ts这样的类型定义文件

如何编写.d.ts这样的类型定义文件

作者: 泡杯感冒灵 | 来源:发表于2022-04-13 17:16 被阅读0次
    类型定义文件是帮助TS文件,去理解引入的JS库里的内容的。因为这些JS库里,没有TS要求的类型的概念。
    我们写代码的时候,通常会遇到一个场景,引入一个类库,发现这个库是用js代码写的,然后ts里用这样的类库就会有问题,导致我们需要安装类库的类型定义文件。安装这样的类型定义文件是非常简单的,但是类型定义文件是怎么写的呢? 原理是什么呢?
    • 我们先在index.html里引入 jquery文件。
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.js"></script>
      <script src="./page.ts"></script>
    </head>
    <body>
      
    </body>
    </html>
    
    • 然后我们可以在page.ts里调用jquery的方法,我们会发现,虽然可以运行,但是编辑器会飘红,告诉我们需要安装jquery 的类型文件。因为jquery 是JS写的。npm i --save-dev @types/jquery
    $(function(){
      alert(123);
    })
    
    image.png

    现在我们不安装别人写的jquery 的类型定义文件,我们自己写一个类型定义文件 jquery.d.ts。帮助page.ts去理解jquery的JS语法。

    • 我们调用的$是一个函数,接收一个参数也是一个函数,$函数返回值是void。参数这个函数返回值也是void
    $(function(){
      alert(123);
    })
    
    • 我们可以这样写,通过declare var定义全局变量;.d.ts 文件中的顶级声明必须以 "declare" 或 "export" 修饰符开头
    //定义全局变量 
    declare var $: (params:()=>void) => void;
    
    • 我们刚才把$定义为一个全局变量。还可以把$定义为一个全局函数
    // 定义全局函数
    declare function $(params:()=>void): void;
    
    函数重载,对一个函数名字,可以写多个全局函数声明。也就是说一个函数,可以有多种形式。
    • 当我们调用的其他方法,编辑器会飘红,因为我们刚才在jquery.d.ts文件里,只是定义了函数接收的参数是一个函数。而不是字符串
    $(function(){
      $('body').html('<div>123</div>');
    })
    
    • 我们可以再次定义一个$全局函数声明,这次接收的参数是一个字符串,返回的是对象,对象里有一个属性html,这属性的类型也是函数,接收一个字符串参数,返回一个对象
    declare function $(params: string): {
      html: (html: string) => {};
    };
    
    • 还可以写的更简洁一点
    interface JqueryInstance {
      html:(html:string)=>JqueryInstance
    }
    // 当传函数的时候,返回值是空
    declare function $(readyFunc: () => void): void;
    // 当传一个选择器的时候,返回值是一个juqery对象
    declare function $(selector: string): JqueryInstance;
    
    函数重载的另外一种写法.这种写法利用了interface 的一种特性,就是在接口里定义两个函数的实现的时候,实际上就是一种函数的重载。表示Jquery 可以有两种实现方式。
    interface Jquery {
      (readyFunc: () => void): void;
      (selector: string): JqueryInstance;
    }
    
    当然,如果只是声明了Jquery 接口,那么$符号是不可以用的,所以可以定义一下$的类型。
    interface Jquery {
      (readyFunc: () => void): void;
      (selector: string): JqueryInstance;
    }
    
    declare var $: Jquery;
    
    如何对对象进行类型定义,以及如何对类进行类型定义,以及命名空间的嵌套
    // new $.fn.init();
    declare namespace $ {
      namespace fn {
        class init {}
      }
    }
    
    $(function(){
      $('body').html('<div>123</div>');
      new $.fn.init();
    })
    
    总之,当我们引入外部的一个库,这个库可能会有一些全局的变量、方法、对象无法被typescript无法识别这些东西,我们就可以通过全局的声明的语法让typescript理解库里的这些东西。让我们在typescript里使用这些变量、方法、对象的时候不再报错。
    • 定义全局变量 用 declare var
    • 定义全局函数 用 declare function
    • 定义全局对象 用 declare namespace
    • 定义全局函数重载的时候,有了两种方式
    declare function $(readyFunc: () => void): void;
    declare function $(params: string): JqueryInstance;
    
    // interface Jquery {
    //   (readyFunc: () => void): void;
    //   (selector: string): JqueryInstance;
    // }
    
    • 如果想要$即是函数又是对象的时候,用interface 就不合适了,还是需要用declare
    declare function $(readyFunc: () => void): void;
    declare function $(params: string): JqueryInstance;
    declare namespace $ {
      namespace fn {
        class init {}
      }
    }
    
    ES6的方式,如何通过.d.ts文件,声明一些模块。
    • 首先安装一下jquery npm install jquery --save.然后在page.ts里引入,会发现报错。原因是 我们的jquery.d.ts文件,并不是模块化声明的。
      image.png
    • 下边我们模块化声明一下 jquery.d.ts。注意 declare 后边跟 module
    // ES6 模块化
    // 定义一个模块叫做jquery 和通过 import引入的 jquery要一致
    declare module 'jquery' {
      interface JqueryInstance {
        html:(html:string)=>JqueryInstance
      }
    
      // 混合类型
      function $(readyFunc: () => void): void;
      function $(params: string): JqueryInstance;
      namespace $ {
        namespace fn {
          class init {}
        }
      }
    }
    
    • 这个时候,通过 import引入的 就不会报错了,但是方法的引用还是会报错。原因是,当我们用模块化定义d.ts文件的时候,记得在最后一定要把外部要用的东西通过export导出去
      image.png
    declare module 'jquery' {
      interface JqueryInstance {
        html:(html:string)=>JqueryInstance
      }
    
      // 混合类型
      function $(readyFunc: () => void): void;
      function $(params: string): JqueryInstance;
      namespace $ {
        namespace fn {
          class init {}
        }
      }
      export = $
    }
    
    • 这样,我们定义了一个jquery的模块,里边有关于jquery的混合类型的定义,最终我们把导出出去,通过这个导出的我们引入后,就可以拿到$上各种方法和命名空间。
    这种是ES6的模块化方式,还有AMD的等等。

    相关文章

      网友评论

          本文标题:如何编写.d.ts这样的类型定义文件

          本文链接:https://www.haomeiwen.com/subject/nnlnsrtx.html