类型定义,可在名称空间上导出类型和类定义

时间:2019-02-05 19:25:42

标签: typescript type-definition

我正在为第三方JS库(Handsontable)的类型定义进行工作,该类库导出顶级API的类和名称空间,概念上是这样的:

import Car from "car-lib";
new Car(); // Create instances
Car.garage.get("mustang"); // Static top-level APIs.

这可以通过导出具有名称空间的class成员的static来建模。

但是,某些类静态名称空间会导出类定义,而我很难正确地暴露类型和类定义以供使用。

示例:

declare namespace Car {
  namespace parts {
    class Engine { vroom(); }
  }
  interface Parts {
    EnginePart: typeof parts.Engine; // Error: Property 'Engine' does not exist on type 'Parts'.
  }
}
declare class Car {
  static parts: Car.Parts;
}

export default Car;

// This works as desired
let engine: Car.parts.Engine;
engine.vroom();

// This should work but I get:
// Error: Type 'Engine' is not a constructor function type.
class V8 extends Car.parts.EnginePart { }

// This does not work, as desired
class V6 extends Car.parts.Engine { } // Error: Property 'Engine' does not exist on type 'Parts'.

the playground中尝试。

我当前的解决方法是给internal namespace a different name,就像_parts一样,但这会导致一些问题:

declare namespace Car {
  namespace _parts {
    class Engine { vroom(); }
  }
  interface Parts {
    EnginePart: typeof _parts.Engine;
  }
}
declare class Car {
  static parts: Car.Parts;
}

export default Car;

// This requires referencing the "_parts" for type annotation, yuck
let engine: Car._parts.Engine;
engine.vroom();

// This works as desired
class V8 extends Car.parts.EnginePart { }

// Problem: this should not be allowed (and will be a runtime error) but it is allowed
class V6 extends Car._parts.Engine { }

the playground中尝试。

执行此操作的正确方法是什么,以使第一个示例的用法(export default Car之后的所有内容)均符合预期?

1 个答案:

答案 0 :(得分:0)

您遇到的困难是由于试图同时解决两个问题而引起的:类型声明和类型发布(缺少更好的术语)。

解决方案是先声明类型,然后将它们连接起来以匹配JavaScript库公开(公开)的形状。

declare namespace CarParts {
  class CarEngine { vroom(); }
}

interface CarParts {
  EnginePart: typeof CarParts.CarEngine;
}

declare namespace Car {
  namespace parts {
    type Engine = CarParts.CarEngine
  }
}
declare class Car {
  static parts: CarParts;
}

export default Car;

let engine: Car.parts.Engine;
engine.vroom();

// This works as desired
class V8 extends Car.parts.EnginePart { }

// This is shown as error as expected
class V6 extends Car.parts.Engine { }

这里是playground link