Skip to content

Instantly share code, notes, and snippets.

@MRezaSafari
Last active February 12, 2025 10:42
Show Gist options
  • Save MRezaSafari/e759b2e509829d9e12ad332ba42253a7 to your computer and use it in GitHub Desktop.
Save MRezaSafari/e759b2e509829d9e12ad332ba42253a7 to your computer and use it in GitHub Desktop.

🔗

Table of contents

Types and Interfaces

  • Types should start with T:
type TComponentProps = {
  name: string;
  age: number;
};
  • Interfaces should start with I:

GOOD

interface IComponentProps {
  name: string;
  age: number;
}

BAD

interface ComponentProps {
  name: string;
  age: number;
}
  • Avoid Explicit Typing When It Can Be Inferred:
// Avoid this:
const [hex, setHex] = useState<string>('#FF0000');

// Use this instead:
const [hex, setHex] = useState('#FF0000');
  • Use interface for Props and Name It with Props Suffix:
// Use interface and name it descriptively with Props suffix
interface IContrastCheckerProps {
  color: string;
  onChange: (value: string) => void;
  className?: string;
}

File Naming

  • Pages and Components use kebab-case
    • Components: To improve file organization, you should create a folder for each component. The folder name should follow the kebab-case convention, and the main file for the component should be named index.tsx.
      • Folder: button-component/
      • Main file: index.tsx (inside the folder)
    • Page file: page.tsx
  • File name must include its type:
    • Utilities: calculate-area.utils.ts
    • Hooks: use-auth.hooks.ts

Exports

  • Pages, Layout, Components and Hooks: Export as default (RAFCE):
const MainPage = () => {
  return <div>Main Page</div>;
}

export default MainPage

const Box = () => {
  return <div>Box Component</div>;
};

export default Box;

const useAuth = () => {
  // Hook logic here
};

export default useAuth;
  • Models and Utilities: Export with named export:
const calculateArea = (width: number, height: number): number => {
  return width * height;
}

export {calculateArea}
type TRectangle = {
  width: number;
  height: number;
};

export type {TRectangle}

Examples of Full Convention

Component Example:

// file: button-component.tsx

interface IButtonProps  {
  label: string;
  onClick: () => void;
};

const Button = ({ label, onClick }: IButtonProps) => {
  return <button onClick={onClick}>{label}</button>;
};

export default Button;

Page Example:

// file: main-page.tsx

const MainPage = () => {
  return <div>Main Page</div>;
}

export default MainPage

Hook Example:

// file: use-auth.hooks.ts

const useAuth = () => {
  const login = (username: string, password: string) => {
    // Logic for login
  };

  const logout = () => {
    // Logic for logout
  };

  return { login, logout };
};

export default useAuth;

Utility Example:

// file: calculate-area.utils.ts

const calculateArea = (width: number, height: number): number => {
  return width * height;
}

export { calculateArea };

Type Example:

// file: rectangle.models.ts

type TRectangle = {
  width: number;
  height: number;
};

export type {TRectangle};

Interface Example:

// file: user.models.ts

interface IUser {
  id: string;
  name: string;
  email: string;
}

export type {IUser};

Imports

  • Import Modules from React directly:
// Preferred
import { FC } from 'react';
const MyComponent: FC = () => <div>Hello</div>;

// Avoid
const MyComponent: React.FC = () => <div>Hello</div>;
  • Order of Imports (implemented by default with third party):
    • Standard library modules (e.g., react, react-dom, axios).
    • Third-party libraries.
    • Absolute imports (e.g., aliases like @/components).
    • Relative imports.
// Example
import { useState } from 'react'; // Standard library
import axios from 'axios';       // Third-party

import { Button } from '@/components/Button'; // Absolute imports

import { calculateArea } from '../../utils/calculate-area.utils'; // Higher-level relative
import './styles.css';          // Same-level relative
  • Named vs. Default Imports:
    • Use named imports for utilities and constants.
    • Use default imports for components, hooks, or major modules.
// Named Import
import { calculateArea } from './utils';

// Default Import
import Header from './components/Header';
  • Avoid Wildcard (* as) Imports:
// Avoid
import * as Utils from './utils';
const area = Utils.calculateArea(5, 10);

// Preferred
import { calculateArea } from './utils';
const area = calculateArea(5, 10);

General Conventions

  • Access Props Individually:
import { FC } from 'react';
import { Slider } from '@dizno/shared/components';

// Define the interface for the props
export interface ISliderProps {
  label: string;
  name: string;
  min: number;
  max: number;
  value: number;
  onChange: (value: number) => void;
}

const SliderField: FC<ISliderProps> = ({
  label,
  name,
  min,
  max,
  value,
  onChange,
}) => (
  <div>
    <h4>{label}</h4>  {/* Access individual prop */}
    <Slider
      name={name}  {/* Access individual prop */}
      min={min}    {/* Access individual prop */}
      max={max}    {/* Access individual prop */}
      value={[value]}  {/* Access individual prop */}
      onValueChange={(val) => onChange(val[0])}  {/* Access individual prop */}
    />
  </div>
);

export default SliderField;
  • use ternary operators instead of short-circuit operators :
// Avoid short-circuit
const count = 0;
return <div>{count && <h1>Messages: {count}</h1>}</div>;

// Prefer ternary
return <div>{count ? <h1>Messages: {count}</h1> : null}</div>;
  • Avoid Nested Ternary Operators:
// Avoid nested ternaries
isSubscribed ? (
  <ArticleRecommendations />
) : isRegistered ? (
  <SubscribeCallToAction />
) : (
  <RegisterCallToAction />
);

// Use a dedicated component
const  CallToActionWidget = ({ subscribed, registered }) => {
  if (subscribed) return <ArticleRecommendations />;
  if (registered) return <SubscribeCallToAction />;
  return <RegisterCallToAction />;
}

return <CallToActionWidget subscribed={isSubscribed} registered={isRegistered} />;
  • Prefer Arrow Functions Over Function Keywords:
//Avoid

// Function declaration
function greet(name) {
  return `Hello, ${name}!`;
}

// Function expression
const greet = function (name) {
  return `Hello, ${name}!`;
};

// React component
function MyComponent({ name }) {
  return <div>Hello, {name}!</div>;
}

//Use

const greet = (name) => {
  return `Hello, ${name}!`;
};

// Single-expression functions can omit braces and `return`
const add = (a, b) => a + b;

// React component example
const MyComponent = ({ name }) => <div>Hello, {name}!</div>;
  • Avoid Inline Helper Functions for Rendering. Break it down to separate component:
//Avoid
const Colors = () => {
    const renderColor = () => {
        return <div>Color</div>
    }
    return (
      <div>
        {renderColor()}
      </div>
    );
  };

export default Colors
  • Keep the app Folder in Next.js Focused on Core Pages and Layouts:

    In Next.js, the app folder should be reserved for the essential pages, layouts, Next.js default files and client-page file. Avoid placing non-essential files or business logic directly in this folder.

  • Define PropsType exactly above the defined function for component:

import Link from 'next/link';
import { FC } from 'react';

import { Box } from '@dizno/shared/components';
import { copyToClipboard, isHex, isLightColor } from '@dizno/shared/utilities';

interface IColorPaletteCardProps {
  colors: Array<string> | null;
  href: string;
  title: string;
  description?: string;
}

const ColorPaletteCard: FC<IColorPaletteCardProps> = ({
  colors,
  href,
  title,
  description,
}) => {

  return (
    <Box width="100%" height="100%">
      ColorPaletteCard
    </Box>
  );
};

export default ColorPaletteCard;
  • keep the primary responsibility of .tsx files focused on rendering JSX elements. This means that .tsx files should mainly handle the structure and presentation of the UI. Any complex logic, utility functions, or business rules should be abstracted into separate files (e.g., hooks, utilities, or models) to maintain a clear separation of concerns.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment