javascript - 如何在动态加载的 Typescript 中扩展类

标签 javascript angular typescript

我通过 npm install @types/googlemaps 将 google maps JS API 与 google.maps 命名空间一起使用。我相信 API 是动态加载的,因此 google.maps JS 全局不能立即可用。

但我不明白为什么我会收到运行时错误:Uncaught ReferenceError: google is not defined 当我尝试使用 扩展 google.maps.Marker 时code>class 但不是 interface

// No problem!
export interface UuidMarker extends google.maps.Marker {
  uuid: string;
}

// Uncaught ReferenceError: google is not defined!!
export class UuidMarker0 extends google.maps.Marker {
  uuid: string;
  constructor(uuid: string, options?: gmMarkerOptions) {
    super(options);
    this.uuid = uuid;
  }
}

仅使用接口(interface)的替代方法

// this works
export function UuidMarkerFactory(uuid: string, marker: google.maps.Marker): google.maps.Marker & {uuid:string} {  
  return Object.assign(marker, {uuid});
}

// this fails with google is not defined!! 
export function UuidMarkerFactory0(uuid: string, options?: any): google.maps.Marker & {uuid:string} {
  if (typeof google == "undefined") return null
  return Object.assign(new google.maps.Marker(options), {uuid});
}

扩展动态加载类的最佳实践是什么?

附加信息

我正在使用 ionic2@RC0,它使用 rollup 来捆绑所有模块。我所有的 typescript 和 node_modules 都被捆绑到一个带有源映射的 main.js 脚本中。实际的 google maps API 由 angular2-google-maps 脚本加载。

如果我使用 interface 进行扩展(这看起来对 typescript 更“友好”),我可以使用什么模式来创建适合 UuidMarker 接口(interface)的对象?

最佳答案

在编译过程中,您不会收到任何错误,因为编译器可以访问您使用 @types 安装的 google.maps 定义。

但是,在运行时,您的文件可能在 google.maps 库加载之前加载,因此解释器无法找到 google.maps.Marker 对象.

只有在您知道 google.maps 文件已成功加载后,您才需要加载您的文件。

UuidMarker 接口(interface)不会出现运行时错误,因为它在运行时不存在。
javascript 中不存在接口(interface),它们仅由 typescript 编译器使用,不会被“翻译”成 js。


你可以通过将类定义放在函数中来做一个技巧。
这样解释器就不会在这个函数被调用之前执行它,这可能是在谷歌地图库加载之后:

interface UuidMarker extends google.maps.Marker {
    uuid: string;
}

let UuidMarker0: { new (uuid: string, options?: gmMarkerOptions): UuidMarker };

function classLoader() {
    UuidMarker0 = class UuidMarker0 extends google.maps.Marker implements UuidMarker {
        uuid: string;

        constructor(uuid: string, options?: gmMarkerOptions) {
            super(options);
            this.uuid = uuid;
        }
    }
}

( playground code which simulates this )

另一种方法是按照您的建议放弃类(class),然后这样做:

function UuidMarker(uuid: string, marker: google.maps.Marker): google.maps.Marker & { uuid: string } {
    return Object.assign(marker, { uuid });
}

编辑

此语法:

type MyType = google.maps.Marker & { uuid: string };

称为Intersection Types这意味着 MyType 拥有 google.maps.Marker 拥有的所有内容以及 uuid 属性。

一个简单的例子:

interface Point {
    x: number;
    y: number;
}

type Point3D = Point & { z: number };

let p1: Point = { x: 0, y: 0 };
let p2: Point3D = { x: 0, y: 0, z: 0 };

关于javascript - 如何在动态加载的 Typescript 中扩展类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40338662/

相关文章:

javascript - 如何使用 React + TypeScript 从 MobX 5 迁移到 MobX 6,而不添加具有 200% 语法噪音的臃肿代码?

javascript - 具有 Store 调度操作的 Angular 单元测试组件

javascript - 如何使用 TypeScript 验证对象与接口(interface)没有重叠的属性?

javascript - 如何使用Drive API设置文件的元数据?

javascript - 如何使用 useReducer 更新嵌套数组?

javascript - 在 Safari 中的 Canvas 页面 iFrame 中使用带有 JS SDK 的 Facebook Graph API 被破坏

javascript - 如何将ajax响应加载到iframe而不是div?

javascript - 如何使用输入值填充 Map<string, string>

javascript - 不滚动子元素滚动div

angular - 如何在 Angular 中使用 import { onError } from 'apollo-link-error' 来处理所有错误