🛡
[TypeScript] 私なりのMicrosoftのコーディングガイドの要約
🌱 はじめに
この記事では、一部抜粋したMicrosoft のコーディングガイド をまとめております。
また、注意事項を確認してください
🌱 命名規則
1. 型名はパスカルケース(PascalCase)を使う
- type userInfo
+ type UserInfo
2. インタフェース名にIを使わない
- interface IUserInfo
+ interface UserInfo
3. 列挙値(enum)の名はパスカルケース(PascalCase)を使う
enum LogLevel {
- info, // camelCase
- warning, // camelCase
- error // camelCase
+ Info, // PascalCase
+ Warning, // PascalCase
+ Error // PascalCase
}
4. 関数名はキャメルケース(camelCase)を使う
- function GetUserData(userId: number) // パスカルケース
+ function getUserData(userId: number) // キャメルケース
5. プロパティ名・ローカル変数名はキャメルケース(camelCase)を使う
- const UserId = 1 // パスカルケース
+ const userId = 1 // キャメルケース
6. private 変数名のの接頭辞に_を使わない
- const _userId = 1
+ const userId = 1
7. 意味のある単語を使うこと
- const usr = 'Ogura'
+ const user = 'Ogura'
- function calc(d: number)
+ function calculateTotal(price: number)
🌱 コンポーネント
1. 1 つのファイルで複数の役割を持たせない
🔧 よくある NG パターン
index.ts
function scan() { ... }
function parse() { ... }
function emit() { ... }
function checkTypes() { ... }
✅ よい構成の例
src/
├── parser.ts // パース処理
├── scanner.ts // スキャナ処理
├── emitter.ts // 出力処理
├── checker.ts // 型チェック処理
2. むやみにファイル追加しない
3. 自動生成されたファイル(.generated.*)は編集しない
🌱 型
1. 他コンポーネントで共有しないなら export しない
- const usr = 'Ogura'
+ const user = 'Ogura'
- function calc(d: number)
+ function calculateTotal(price: number)
2.グローバル名前空間には追加しない
❌ ダメな例(グローバルを汚染する)
これらは他のコードやライブラリと名前がかぶるリスクがあり、予期せぬバグの温床になります。
global.d.ts
// どこでも User 型が使えるが、衝突や上書きの原因に
interface User {
name: string;
age: number;
}
✅ 良い例(スコープを限定する)
types/user.ts
// types/user.ts に定義し、必要なファイルでインポート
export interface User {
name: string;
age: number;
}
3. 共通の型は types.ts にまとめる
🔧 よくある NG パターン
parser.ts
interface Config {
mode: string;
verbose: boolean;
}
import { Config } from "./types";
function parseConfig(config: Config) {
// ...
}
✅ よい構成の例
src/
├── types.ts // 共通の型
├── parser.ts // パース処理
types.ts
export interface Config {
mode: string;
verbose: boolean;
}
parser.ts
import { Config } from "./types";
function parseConfig(config: Config) {
// ...
}
4. 型定義はファイルの最初に記載する
- function scan() { ... }
- function parse() { ... }
- type Scan { ... }
- type Parse { ... }
+ type Scan { ... }
+ type Parse { ... }
+ function scan() { ... }
+ function parse() { ... }
🌱 nullとundefined
1. undefinedを使いnullは使わない。
なぜ undefined を使って null は避けるのか?
- 一貫性のため
JavaScript では、初期化されていない変数や存在しないプロパティは undefined になります。
let a;
console.log(a); // undefined
API や内部コードでundefinedを使うことで、デフォルトの挙動と合わせられる。
- 二重管理の複雑さを避ける
nullとundefinedの両方を使うと、「どっちが来るか」を常に意識しないといけません。
function getName(): string | null | undefined {
// 呼び出し側は3通りの分岐が必要
}
undefinedに統一すれば、分岐の数を減らし、コードがシンプルになる。
- 型システムとの相性が良い
TypeScript の型チェックでは、undefinedの方が柔軟に扱えます。
Partial<T>や?をつけたオプショナル型はundefinedを前提としています。
interface User {
name?: string; // name: string | undefined
}
🌱 前提条件
1.Node や Symbol などのオブジェクトは作成元以外では変更しない
❌ 悪い例:ノードを勝手に書き換える
function tamperNode(node: ts.Node) {
node.kind = ts.SyntaxKind.StringLiteral; // ❌ 他の処理にも影響する
}
✅ 良い例:読み取り専用として扱う
function tamperNode(node: ts.Node) {
node.kind = ts.SyntaxKind.StringLiteral; // ❌ 他の処理にも影響する
}
2. 配列は基本的に不変として扱う
配列の値は部分的に更新をしない
❌ 悪い例:配列やオブジェクトを直接変更
const user = { name: "Alice", age: 30 };
user.age = 31; // ← 直接変更(副作用の原因)
const list = [1, 2, 3];
list.push(4); // ← 元の配列を直接変更
✅ 良い例:コピーして変更(不変)
const user = { name: "Alice", age: 30 };
const updatedUser = { ...user, age: 31 }; // 新しいオブジェクトを作る
const list = [1, 2, 3];
const newList = [...list, 4]; // 新しい配列を作る
✅ より強力に:readonly を使う
interface User {
readonly id: number;
readonly name: string;
}
const user: User = { id: 1, name: "Alice" };
// user.name = "Bob"; // ❌ エラー!readonlyなので変更不可
const numbers: readonly number[] = [1, 2, 3];
// numbers.push(4); // ❌ エラー
🌱 コメント
1. JSDoc 形式を使用(関数・型・クラスなど)
/**
* ユーザー情報を取得する
* @param userId - 対象のユーザーID
*/
function fetchUser(userId: number): UserInfo {
// ...
}
Discussion