项目总结 - ts中的declare let type: any和对.d.ts文件类型的认识

本文探讨了在Angular5.0+Ionic3.0项目中,如何将全JavaScript编写的插件引入到TypeScript模块。通过解析类型定义文件(.d.ts)的作用,阐述了JavaScript库在TypeScript环境中实现静态类型推导的方法。

项目中用的是angular5.0+ionic3.0,由于现在angular现在都是用typescript写的了,虽然说typescript是Javascript的超集,但是在项目中还是会有一些问题,那就是全js写的插件怎么能引入到typescript写的模块呢?
TypeScript 的核心在于静态类型,我们在编写 TS 的时候会定义很多的类型,但是主流的库都是 JavaScript 编写的,并不支持类型系统。那么如何让这些第三方库也可以进行类型推导呢?
这篇文章我们来讲解 JavaScript 和 TypeScript 的静态类型交叉口 —— 类型定义文件。
之前在做项目的时候,老是看到这种写法,请看下面的代码:

        import { ViewChild, ElementRef } from "@angular/core";
        import { Company } from "../company/company";
        import { Electronic } from "../sign/electronic/electronic";
        import { Auth } from "../auth-pop/auth";
        import { Credit } from '../credit-pop/credit';
        declare let Talking: any;
        declare let Push: any;
        declare let cordova: any;
        declare let Swiper: any;

从上面的代码我们可以看到有import的导入,还有declare的声明,为什么会这样写?下面会一一讲解

    import { Electronic } from "../sign/electronic/electronic";

这行代码表示从electronic.ts引入我们定义的Electronic类,我们先看一下electronic.ts

    import { Component } from "@angular/core";
    import { NavController, NavParams, ModalController,Tabs, Events } from "ionic-angular";
    import { CallNumber } from '@ionic-native/call-number';
    import { Storage } from "@ionic/storage";
    
    @Component({
      templateUrl: "electronic.html",
      providers: [CallNumber]
    })
    export class electronic {
      constructor(
      ) {      
      }
      ngOnInit() {
      }
      ionViewDidEnter() {
      }
    }

这个导入想必大家都知道,那这个这个呢?

    import { ViewChild, ElementRef } from "@angular/core";

ViewChild和ElementRef都是封装好的插件,它们也都是用js写的,为什么它们可以用import的方式导入进来呢,仔细去查看了一下,发现它们都有一个.d.ts结尾的文件
ViewChild ===》di.d.ts
ElementRef ===》element_ref.d.ts
可以看到它们都有一个对应的.d.ts的文件
那么这个.d.ts的文件到底是什么样的?有什么作用呢?
在 TypeScript 中,我们可以很简单的,在代码编写中定义类型:

    interface IBaseModel {
        say(keys: string[] | null): object
    }
    
    class User implements IBaseModel {
        name: string
        constructor (name: string) {
            this.name = name
        }
    }

但是主流的库都是 JavaScript 编写的,TypeScript 身为 JavaScript 的超集,自然需要考虑到如何让 JS 库也能定义静态类型。
TypeScript 经过了一系列的摸索,先后提出了 tsd(已废弃)、typings(已废弃),最终在 TypeScript 2.0 的时候重新整理了类型定义,提出了 DefinitelyTyped。
DefinitelyTyped 就是让你把 “类型定义文件(*.d.ts)”,发布到 npm 中,配合编辑器(或插件),就能够检测到 JS 库中的静态类型。

类型定义文件的以 .d.ts 结尾,里面主要用来定义类型。
我们来看一下element_ref.d.ts

    /**
     * @license
     * Copyright Google Inc. All Rights Reserved.
     *
     * Use of this source code is governed by an MIT-style license that can be
     * found in the LICENSE file at https://angular.io/license
     */
    /**
     * A wrapper around a native element inside of a View.
     *
     * An `ElementRef` is backed by a render-specific element. In the browser, this is usually a DOM
     * element.
     *
     * @security Permitting direct access to the DOM can make your application more vulnerable to
     * XSS attacks. Carefully review any use of `ElementRef` in your code. For more detail, see the
     * [Security Guide](http://g.co/ng/security).
     *
     * @stable
     */
    export declare class ElementRef {
        /**
         * The underlying native element or `null` if direct access to native elements is not supported
         * (e.g. when the application runs in a web worker).
         *
         * <div class="callout is-critical">
         *   <header>Use with caution</header>
         *   <p>
         *    Use this API as the last resort when direct access to DOM is needed. Use templating and
         *    data-binding provided by Angular instead. Alternatively you take a look at {@link Renderer}
         *    which provides API that can safely be used even when direct access to native elements is not
         *    supported.
         *   </p>
         *   <p>
         *    Relying on direct DOM access creates tight coupling between your application and rendering
         *    layers which will make it impossible to separate the two and deploy your application into a
         *    web worker.
         *   </p>
         * </div>
         * @stable
         */
        nativeElement: any;
        constructor(nativeElement: any);
    }

从上面的代码我们可以提炼出最重要的一行代码

    export declare class ElementRef {

从这行代码中我们也看到了declare
declare
declare 可以创建 *.d.ts 文件中的变量,declare 只能作用域最外层

    declare var foo: number;
    declare function greet(greeting: string): void;
    
    declare namespace tasaid {
        // 这里不能 declare
        interface blog {
            website: 'http://tasaid.com'
        } 
    }

基本上顶层的定义都需要使用 declare, class 也是:

    declare class User {
        name: string
    }
// plugins/dropdown-scroll-listener.ts // 标记是否已经注入过,防止重复绑定 let hasInjected = false // 定义 uni-app 页面实例的基本结构 interface UniPage { onLoad?(...args: any[]): void onPageScroll?(res: { scrollTop: number }): void [key: string]: any // 支持动态属性,如 __dropdown_scroll_bound__ } // 重写 Page 构造函数的类型(uni-app 中 Page 是全局对象) declare const Page: { new (): UniPage prototype: UniPage onLoad?: (...args: any[]) => void // eslint-disable-next-line @typescript-eslint/no-explicit-any (options: Record<string, any>): void } // eslint-disable-next-line @typescript-eslint/no-explicit-any declare const uni: any /** * 启用下拉菜单滚动监听器 * * 自动为所有页面注入 onPageScroll 钩子, * 并通过 uni.$emit('onPageScroll', res) 进行事件广播。 */ export function useDropdownScrollListener(): void { console.log('🚀 ~ useDropdownScrollListener ~ hasInjected:', hasInjected) if (hasInjected) return hasInjected = true if (typeof globalThis !== 'undefined' && typeof uni !== 'undefined') { const originalOnLoad = Page.onLoad // 重写 Page.onLoad,拦截每个页面的初始化 // eslint-disable-next-line @typescript-eslint/no-explicit-any Page.onLoad = function (this: UniPage, ...args: any[]) { // 调用原始的 onLoad(如果存在) if (originalOnLoad && typeof originalOnLoad === 'function') { originalOnLoad.apply(this, args) } // 动态添加 onPageScroll 钩子 this.onPageScroll = (res): void => { console.log('🚀 ~ useDropdownScrollListener ~ res:', res) uni.$emit('onPageScroll', res) } } console.log('[Dropdown Scroll Listener] 已注入 Page.onLoad 拦截器') } else { console.warn('[Dropdown] 当前环境不支持 Page Hook,可能无法监听页面滚动') } } 在小程序的main.ts中调用了但也成功了,但是滚动的时候没有触发
10-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值