如何在动态加载的Typescript中扩展一个类

mic*_*ael 5 javascript typescript angular

我正在使用谷歌地图JS API和google.maps命名空间 npm install @types/googlemaps.我相信API是动态加载的,因此google.mapsJS全局不会立即可用.

但我不明白为什么我会得到运行时错误:Uncaught ReferenceError: google is not defined当我尝试google.maps.Marker使用a class而不是a 进行扩展时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;
  }
}
Run Code Online (Sandbox Code Playgroud)

仅使用接口的替代方法

// 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});
}
Run Code Online (Sandbox Code Playgroud)

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

附加信息

我正在使用ionic2@RC0哪个用于rollup捆绑所有模块.我的所有打字稿node_modules都捆绑在一个main.js包含源地图的脚本中.实际的Google Maps API由angular2-google-maps脚本加载.

如果我使用interface(似乎更多的打字稿"友好")扩展,我可以使用什么模式来创建适合UuidMarker界面的对象?

Nit*_*mer 7

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

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

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

您没有获得UuidMarker接口的运行时错误,因为它在运行时不存在.
javascript中不存在接口,它们仅由typescript编译器使用,不会被"转换"为js.


你可以通过将类定义放在函数中来做一个技巧.
这样解释器在调用此函数之前不会执行它,这可以在google maps lib加载之后执行:

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

(模拟此的游乐场代码)

另一种方法是按照你的建议放弃课程,然后做:

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

编辑

这个语法:

type MyType = google.maps.Marker & { uuid: string };
Run Code Online (Sandbox Code Playgroud)

被称为交叉类型,它意味着拥有加上属性的MyType所有东西.google.maps.Markeruuid

一个简单的例子:

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 };
Run Code Online (Sandbox Code Playgroud)