ろぼいんブログ
更新:

ESLintでTypeScriptのクラスのpublicやprivateを強制する方法

TypeScriptを使う開発において、コードのメンテナンス性と可読性を保つことは非常に重要です。とくに、大規模なプロジェクトやチームでの開発では、コードの一貫性を保つためのルールが求められます。

この記事では、ESLintと@typescript-eslintプラグインを使用して、TypeScriptのクラスメンバーに対するアクセシビリティ(publicprotectedprivate)の明示を強制する方法について解説します。

(window.powerTag.Init = window.powerTag.Init || []).push(function () { window.powerAPITag.display("pw_41759"); });

@typescript-eslint/explicit-member-accessibilityルール

このルールを使うと、TypeScriptのクラスメンバーについて、アクセシビリティを明示的に宣言することを強制できます。これにより、クラスの外部からアクセスできるプロパティやメソッドが明確になり、コードの可読性が向上します。

通常のJavaScriptと違い、TypeScriptではアクセシビリティ修飾子(publicprotectedprivate)を使用できます。

たとえば、次のようにクラスを定義すると、Dog.bark()メソッドはクラスの外部から呼びだせますが、Dog.eat()メソッドはクラスの外部から呼びだせません。また、Dog.sleep()メソッドは、Dogクラス自身と、Dogクラスを継承したサブクラスからのみ呼びだせます。

try{(()=>{function a(e){if(!e)return;let t=e.getAttribute("tabindex")!==null,n=e.scrollWidth>e.clientWidth;n&&!t?e.setAttribute("tabindex","0"):!n&&t&&e.removeAttribute("tabindex")}var u=window.requestIdleCallback||(e=>setTimeout(e,1)),i=window.cancelIdleCallback||clearTimeout;function l(e){let t=new Set,n,r;return new ResizeObserver(c=>{c.forEach(o=>t.add(o.target)),n&&clearTimeout(n),r&&i(r),n=setTimeout(()=>{r&&i(r),r=u(()=>{t.forEach(o=>e(o)),t.clear()})},250)})}function d(e,t){e.querySelectorAll?.(".expressive-code pre > code").forEach(n=>{let r=n.parentElement;r&&t.observe(r)})}var s=l(a);d(document,s);var b=new MutationObserver(e=>e.forEach(t=>t.addedNodes.forEach(n=>{d(n,s)})));b.observe(document.body,{childList:!0,subtree:!0});document.addEventListener("astro:page-load",()=>{d(document,s)});})();}catch(e){console.error("[EC] tabindex-js-module failed:",e)}try{(()=>{function i(o){let e=document.createElement("pre");Object.assign(e.style,{opacity:"0",pointerEvents:"none",position:"absolute",overflow:"hidden",left:"0",top:"0",width:"20px",height:"20px",webkitUserSelect:"auto",userSelect:"all"}),e.ariaHidden="true",e.textContent=o,document.body.appendChild(e);let a=document.createRange();a.selectNode(e);let n=getSelection();if(!n)return!1;n.removeAllRanges(),n.addRange(a);let r=!1;try{r=document.execCommand("copy")}finally{n.removeAllRanges(),document.body.removeChild(e)}return r}async function l(o){let e=o.currentTarget,a=e.dataset,n=!1,r=a.code.replace(/\u007f/g,` `);try{await navigator.clipboard.writeText(r),n=!0}catch{n=i(r)}if(!n||e.parentNode?.querySelector(".feedback"))return;let t=document.createElement("div");t.classList.add("feedback"),t.append(a.copied),e.before(t),t.offsetWidth,requestAnimationFrame(()=>t?.classList.add("show"));let c=()=>!t||t.classList.remove("show"),d=()=>{!t||parseFloat(getComputedStyle(t).opacity)>0||(t.remove(),t=void 0)};setTimeout(c,1500),setTimeout(d,2500),e.addEventListener("blur",c),t.addEventListener("transitioncancel",d),t.addEventListener("transitionend",d)}function s(o){o.querySelectorAll?.(".expressive-code .copy button").forEach(e=>e.addEventListener("click",l))}s(document);var u=new MutationObserver(o=>o.forEach(e=>e.addedNodes.forEach(a=>{s(a)})));u.observe(document.body,{childList:!0,subtree:!0});document.addEventListener("astro:page-load",()=>{s(document)});})();}catch(e){console.error("[EC] copy-js-module failed:",e)}
class Dog {
constructor(name: string) {
// ...
}
public bark() {
// ...
}
private eat() {
// ...
}
protected sleep() {
// ...
}
}

このように、アクセシビリティ修飾子を使用することで、クラスのメンバーに対するアクセスレベルを明確にできます。

こうすることで、外部からの呼びだしを意図していないメソッドやプロパティに対して、誤ってアクセスすることを防げます。さらに、privateなメソッドやプロパティがクラスの内部でのみ使用されることを保証できるため、コードを変更しやすくなります。

アクセシビリティ修飾子を省略した場合、TypeScriptはデフォルトでpublicとして扱います。しかし、アクセシビリティ修飾子が省略されている場合、単なる書き忘れなのか、publicとして意図されているのかが分かりにくくなります。

ESLintの@typescript-eslint/explicit-member-accessibilityルールを使用することで、このようなアクセシビリティ修飾子を明示的に記述することを強制できます。

インストール方法

まず、まだインストールしていない場合はESLintと@typescript-eslintプラグインをインストールします。

Terminal window
npm install --save-dev eslint @typescript-eslint/eslint-plugin

設定方法

@typescript-eslintをインストールしたら、プラグインとルールを有効化します。

.eslintrc.json
{
"plugins": [
"@typescript-eslint"
],
"rules": {
"@typescript-eslint/explicit-member-accessibility": "error"
}
}

たいていの場合はこれで十分ですが、より詳細な設定も可能です。たとえば、次のようにすると、特定の拡張子をもつファイルに対してのみこのルールを有効にできます。これは、JavaScriptファイルとTypeScriptファイルが混在しているプロジェクトで便利です。

.eslintrc.json
{
"rules": {
// ルールをデフォルトで無効にする
"@typescript-eslint/explicit-member-accessibility": "off"
},
"overrides": [
{
// TypeScriptファイルに対してのみ有効にする
"files": ["*.ts", "*.mts", "*.cts", "*.tsx"],
"rules": {
"@typescript-eslint/explicit-member-accessibility": "error"
}
}
]
}

オプション

explicit-member-accessibilityルールは、他にもさまざまなオプションでカスタマイズが可能です。たとえば、次の設定では、デフォルトですべてのメンバーにアクセシビリティを明示することを要求し、一部のメンバータイプに対しては特定のアクセシビリティを禁止します。

.eslintrc.json
{
"rules": {
"@typescript-eslint/explicit-member-accessibility": [
"error",
{
"accessibility": "explicit",
"overrides": {
"accessors": "explicit",
"constructors": "no-public",
"methods": "explicit",
"properties": "off",
"parameterProperties": "explicit"
}
}
]
}
}

この設定により、プロパティに対してはアクセシビリティの明示を求めず("properties": "off")、他のメンバー(アクセサーやメソッドなど)については明示を要求します。また、コンストラクターにpublicを使用することを禁止します("constructors": "no-public")。

(window.powerTag.Init = window.powerTag.Init || []).push(function () { window.powerAPITag.display("pw_41759"); });

コード例

以下は、explicit-member-accessibilityルールが有効な場合の正しいコードの例と、不適切なコードの例です。

正しいコード例(デフォルト設定):

class Animal {
public constructor(public breed, name) {
this.animalName = name;
}
private animalName: string;
public get name(): string {
return this.animalName;
}
public set name(value: string) {
this.animalName = value;
}
public walk() {
// method
}
}

不適切なコード例:

class Animal {
constructor(name) {
this.animalName = name;
}
animalName: string;
get name(): string {
return this.animalName;
}
set name(value: string) {
this.animalName = value;
}
walk() {
// method
}
}

この例では、すべてのクラスメンバーにアクセシビリティ修飾子が欠けています。修飾子を追加することで、クラスの使用方法やメンバーへのアクセスレベルが明確になります。

まとめ

@typescript-eslint/explicit-member-accessibilityルールを使用することで、TypeScriptのクラスメンバーに対するアクセシビリティ修飾子の明示を強制し、コードの可読性を高めることができます。

(window.powerTag.Init = window.powerTag.Init || []).push(function () { window.powerAPITag.display("pw_41759"); });

おすすめアイテム

※このリンクを経由して商品を購入すると、当サイトの運営者が報酬を得ることがあります。詳細はこちら

このサイトを支援する

Buy Me a CoffeeまたはGitHub Sponsorsで支援していただけると、サイトの運営やコンテンツ制作の励みになります。定期的な支援と一度限りの支援がありますので、お間違いのないようにお願いします。

Buy me a coffee

著者のアイコン画像

生まれた時から、母国語よりも先にJavaScriptを使っていました。ネットの海のどこにもいなくてどこにでもいます。

Webフロントエンドプログラマーで、テクノロジーに関する話題を追いかけています。動画編集やプログラミングが趣味で、たまにデザインなどもやっています。主にTypeScriptを使用したWebフロントエンド開発を専門とし、便利で実用的なブラウザー拡張機能を作成しています。また、個人ブログを通じて、IT関連のニュースやハウツー、技術的なプログラミング情報を発信しています。