如何在 TypeScript 中模仿私有和 public 构造函数重载

How to mimic private and public constructor overloads in TypeScript

我有一个 class 打算从两个不同的地方构建,在 class 外部和 class 内部。

定义 class 的模块提供了一个对象,class 在其闭包环境中捕获该对象。

从 class 内部(例如方法调用),class 是用对象构造的。

这是 JavaScript 中的样子:

const private_accessor = ...;

export class T {
    create() {
        return new T(private_accessor);
    }

    constructor(key) {
        if (key === private_accessor) {
            // trusted call
        } else {
            // outside callee
        }
    }
}

我们可以将构造函数键入 constructor(key?: object),但实际上,这并不能反映 class 的用途。

我认为最直观的答案是:

const private_accessor: object_type = ...;

export class T {
    create(): T {
        return new T(private_accessor);
    }

    private constructor(key: object_type);
    public constructor();
    constructor(key /* object_type? */) {
        if (key === private_accessor) {
            // trusted call
        } else {
            // outside callee
        }
    }
}

由于私有重载是一个实现细节,无论如何都无法从外部被调用方工作,因此没有理由公开类型重载。

但是 TSC 不允许这样做。

还有其他方法可以实现我想要做的事情吗?

虽然拥有多个具有不同可见性的 call/construct 签名会很好,但语言不支持。请参阅 microsoft/TypeScript#9592,它作为设计限制被关闭:它似乎不是一个足够常见的用例,不足以保证额外的工作和编译器的复杂性。


相反,我建议您考虑使用一组单独的面向外部和内部的接口,其中外部接口仅包含“public”功能,内部接口还包含“私有”功能。当您 export 您的 values/types 时,仅公开 public 功能:

class T {
  create(): T {
    return new T(private_accessor);
  }

  constructor(key?: object_type) {
    if (key === private_accessor) {
      // trusted call
    } else {
      // outside callee
    }
  }
}

// public version of T 
const Tpublic: new () => T = T;

export { Tpublic as T }; // renamed

这里 T class 的内部版本可以用两种方式构造,但是您将它导出为只有无参数 construct signature 的东西。因此阻止导入此库的其他代码使用“私有”构造函数:

import { T } from "./lib";

const t = new T(); // okay
t.create(); // okay

new T("something"); // error!
//    ~~~~~~~~~~~ Expected 0 arguments, but got 1.ts

CodeSandbox link to code