👀

.d.ts での可視性を制御する tsconfig の stripInternal 設定について

2022/08/11に公開

TSConfig の compilerOption に stripInternal という設定があります。

TSConfig Reference #Strip Internal

この設定を有効にすると、JSDoc に @internal を指定したコード(クラス、メソッド、変数、関数)がコンパイル時に生成される .d.ts へ出力されなくなります。

これにより、C# や Kotlin の internal、Java の package private のようなアクセス修飾子相当の振る舞いを TypeScript で実現できます。

TypeScript では、export を使ってコンパイル後のモジュールを構成する必要がありますが、モジュール内部に閉じたアクセス制御を行うことはできません。stripInternal を設定することで、モジュール内でのみ公開するコードを明示的に指定できます。

demo.ts
export const extenalVariable = "foo";

/** 
 * この関数はモジュール内でしか利用できない
 * @internal
 */
export const internalFunction = () => "bar";

/** 
 * このクラスはモジュール内でしか利用できない
 * @internal
 */
export class InternalClass {
    publicMethod() {
      return true;
    }
}

export class ExtenalClass {
  publicMethod() {
    return true;
  }
  /**
   * このメソッドはモジュール内でしか利用できない
   * @internal
   */
  internalMethod() {
    return true;
  } 
}

上記をコンパイルした場合、.d.ts ファイルは以下になります。@internal が指定された関数やクラス、メソッドが出力されていないことが分かります。これにより外部からは参照ができなくなります(コンパイルエラーになる)。

demo.d.ts
export declare const extenalVariable = "foo";
export declare class ExternalClass {
  publicMethod(): boolean;
}

interface にも指定できますが、interface 定義にのみ反映されます。実装側で @internal を指定し忘れていた場合でも静的解析でエラーなどは出ないため注意してください。

interface Interface {
    publicMethod: () => boolean;
    /**
     * .d.ts には表示されない
     * @internal
     */
    internalMethod: () => boolean;
}

export class ExternalClass implements Interface {
    publicMethod() {
        return true;
    }
    // 明示的に JSDoc で指定していないため .d.tsに出力される
    internalMethod() {
        return true;
    } 
}

まとめ

コードが肥大化していくと、モジュール内だけで利用するロジックが出現してきて、外部から見えなくしたい場面が出てきます。TypeScript では stripInternal 設定をすることで制御できるようになるので、複数のモジュールを利用している場合の参考にどうぞ。

GitHubで編集を提案

Discussion