Files
twenty/packages/twenty-docs/l/ja/developers/contribute/style-guide.mdx
T
github-actions[bot] a0493dbc4b i18n - docs translations (#22276)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-06-29 05:04:26 +02:00

177 lines
5.4 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: スタイルガイド
icon: paintbrush
description: Twentyに貢献するためのコード規約とベストプラクティス。
---
## React
### 関数コンポーネントのみ
常に名前付きエクスポートの TSX 関数コンポーネントを使用してください。
```tsx
// ❌ Bad
const MyComponent = () => {
return <div>Hello World</div>;
};
export default MyComponent;
// ✅ Good
export function MyComponent() {
return <div>Hello World</div>;
};
```
### プロパティ
`{ComponentName}Props` という名前の型を作成する。 分割代入を使用する。 `React.FC` を使用しない。
```tsx
type MyComponentProps = {
name: string;
};
export const MyComponent = ({ name }: MyComponentProps) => <div>Hello {name}</div>;
```
### 単一変数によるプロップスのスプレッドは禁止
```tsx
// ❌ Bad
const MyComponent = (props: MyComponentProps) => <Other {...props} />;
// ✅ Good
const MyComponent = ({ prop1, prop2 }: MyComponentProps) => <Other {...{ prop1, prop2 }} />;
```
## 状態管理
### グローバル状態には Jotai の atom を使用
```tsx
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
export const myAtomState = createAtomState<string>({
key: 'myAtomState',
defaultValue: 'default value',
});
```
* prop drilling よりも atom を優先する
* 状態管理に `useRef` を使用しない — `useState` または atom を使用する
* リストには atom ファミリーとセレクターを使用する
### 不要な再レンダーを避ける
* `useEffect` とデータ取得は同一階層のサイドカーコンポーネントに切り出す
* `useEffect` よりもイベントハンドラー(`handleClick`、`handleChange`)を優先する
* `React.memo()` は使用しない — 代わりに根本原因を修正する
* `useCallback` および `useMemo` の使用を制限する
```tsx
// ❌ Bad — useEffect in the same component causes re-renders
export const Page = () => {
const [data, setData] = useAtomState(dataState);
const [dep] = useAtomState(depState);
useEffect(() => { setData(dep); }, [dep]);
return <div>{data}</div>;
};
// ✅ Good — extract into sibling
export const PageData = () => {
const [data, setData] = useAtomState(dataState);
const [dep] = useAtomState(depState);
useEffect(() => { setData(dep); }, [dep]);
return <></>;
};
export const Page = () => {
const [data] = useAtomState(dataState);
return <div>{data}</div>;
};
```
## TypeScript
* **`interface` より `type`** — より柔軟で、合成しやすい
* **enum より文字列リテラル** — ただし GraphQL コード生成の enum と内部ライブラリ API は除く
* **`any` は禁止** — 厳格な TypeScript を適用
* **型インポートは禁止** — 通常のインポートを使用(Oxlint の `typescript/consistent-type-imports` で強制)
* **[Zod](https://github.com/colinhacks/zod) を使用**して、型未定義オブジェクトを実行時に検証する
## JavaScript
```tsx
// Use nullish-coalescing (??) instead of ||
const value = process.env.MY_VALUE ?? 'default';
// Use optional chaining
onClick?.();
```
## 命名について
* **変数**: camelCase、意味がわかる名前(`value` ではなく `email`、`fm` ではなく `fieldMetadata`
* **定数**: SCREAMING_SNAKE_CASE
* **型/クラス**: PascalCase
* **ファイル/ディレクトリ**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`)
* **イベントハンドラー**: `handleClick` (ハンドラー関数として `onClick` は使用しない)
* **コンポーネントのプロップス**: コンポーネント名を接頭辞に付ける(`ButtonProps`
* **スタイル付きコンポーネント**: `Styled` を接頭辞に付ける(`StyledTitle`
## スタイリング
[Linaria](https://github.com/callstack/linaria) の styled components を使用する。 テーマの値を使用し、`px`、`rem`、色のハードコードは避ける。
```tsx
// ❌ Bad
const StyledButton = styled.button`
color: #333333;
font-size: 1rem;
margin-left: 4px;
`;
// ✅ Good
const StyledButton = styled.button`
color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.md};
margin-left: ${({ theme }) => theme.spacing(1)};
`;
```
## インポート
相対パスの代わりにエイリアスを使用する:
```tsx
// ❌ Bad
import { Foo } from '../../../../../testing/decorators/Foo';
// ✅ Good
import { Foo } from '~/testing/decorators/Foo';
import { Bar } from '@/modules/bar/components/Bar';
```
## フォルダ構成
```
front
└── modules/ # Feature modules
│ └── module1/
│ ├── components/
│ ├── constants/
│ ├── contexts/
│ ├── graphql/ (fragments, queries, mutations)
│ ├── hooks/
│ ├── states/ (atoms, selectors)
│ ├── types/
│ └── utils/
└── pages/ # Route-level components
└── ui/ # Reusable UI components (display, input, feedback, ...)
```
* モジュールは他のモジュールからインポートしてよいが、`ui/` は依存関係を持たない状態を保つこと。
* モジュール専用コードには `internal/` サブフォルダを使用する。
* コンポーネントは 300 行未満、サービスは 500 行未満