Optimizing Team Productivity: Key Front-End Coding Practices with TypeScript and React
Atsushi Suzuki
Posted on March 18, 2024
With the recent expansion of our development team, we found it crucial to establish a front-end coding convention aimed at preserving readability and maintainability. This article focuses primarily on practices within TypeScript and React. We hope this serves as a valuable resource for you.
Naming Conventions for Functions and Variables
CONSTANT_CASE
Global constants are named in all uppercase letters, with words separated by underscores.
const MAX_USERS = 5;
UpperCamelCase
Classes, types, and type parameters follow the UpperCamelCase convention, starting with a capital letter.
class UserAccount {}
type UserType = { name: string; age: number; };
lowerCamelCase
Variables, parameters, functions, methods, properties, and module aliases adhere to the lowerCamelCase convention, starting with a lowercase letter.
let userName: string = "John Doe";
function getUserInfo(userId: number) {...}
Handling Proper Nouns
Proper nouns also follow the naming conventions, adapting to camelCase as appropriate.
-
URLPath
→UrlPath
,urlPath
-
iOSDevice
→IosDevice
,iosDevice
Usage of Multiple Words
Names other than root App
or basic components are constructed using multiple words to ensure clarity.
// Good
const TodoList = () => <div>...</div>;
type ShopCategory = "Grocery Store" | "Cafe" | "Italian Restaurant";
Initials and Abbreviations
Project-specific abbreviations that might not be immediately clear to new team members should be avoided.
// Good
let backendManager = new BackendManager();
Comments
Avoid Stating the Obvious
Omit comments when the name itself makes the intent clear.
Explain the "Why," Not the "What"
Comments should clarify why a piece of code is written, not what it does.
// WHY: To ensure the user is of legal age
if (user.age >= 18) {...}
Marking Code Imperfections
Use TODO
, NOTE
, FIXME
to highlight areas needing improvement or attention.
// TODO: Improve performance
// FIXME: Incomplete error handling
TypeScript-Specific Guidelines
Favor named export Over default export
Named exports enhance code clarity and reusability.
// Good
export const getUser = () => {...};
Prefer type Over interface
type
is favored for its flexibility and the ease with which its contents can be inspected in VS Code.
type User = {
name: string;
age: number;
};
Use Union Types Instead of enum
Union Types are preferred for their direct impact on the compiled code, utilizing TypeScript's type advantages without runtime overhead.
type Role = "admin" | "user" | "guest";
Prioritize undefined Over null
Using undefined
over null
simplifies the TypeScript type system and is generally recommended.
let user: User | undefined = undefined;
Components
Append Basic Component Names Last
Names end with basic component descriptors (Container, View, Button, etc.) to clarify their roles.
const UserProfileContainer = () => <div>...</div>;
Order of Words
Start with the most general word and end with descriptive modifiers for clear naming.
// Good
const SearchResultList = () => <div>...</div>;
Tightly Coupled Components
Names of components that are closely related should reflect their association, often by prefixing with the parent component's name.
const TodoList = () => <ul>...</ul>;
const TodoListItem = () => <li>...</li>;
Typing Props
Clearly define expected properties through type annotations to maintain component contract integrity.
type Props = {
onClick: () => void;
title: string;
};
const Button: React.FC<Props> = ({ onClick, title }) => (
<button onClick={onClick}>{title}</button>
);
Avoid the Spread Syntax in Props
To prevent unnecessary properties from being passed, use the spread syntax cautiously.
// Good
const userDetails = { name: "John", age: 30 };
<UserProfile {...userDetails} />
Writing Conditional Statements
Always use {} to wrap if statements
Even when the statement can be written in one line, wrapping it in braces enhances readability.
// Not recommended
if (condition) return;
// Recommended
if (condition) {
return;
}
Comparing Boolean Values
Prefer comparing directly to true
Explicit comparison makes the intention of your code clearer.
// Not recommended
if (!disabled) {
doSomething();
}
// Recommended
if (enabled) {
doSomething();
}
For boolean variables, use prefixes like is
, has
, can
, should
to clarify their type. However, it's common practice not to apply this rule to component props.
// Not recommended
<RoundButton isDisabled={true} />
// Recommended
<RoundButton disabled />
Using Ternary Operators
Avoid ternary operators when not using the return value
// Not recommended
condition ? doSomething() : doSomethingElse();
// Recommended
if (condition) {
doSomething();
} else {
doSomethingElse();
}
Choosing Between Switch Statements and Map Objects
Consider Map objects for managing key-value based logic
Maps can be particularly useful for handling cases based on key-value pairs.
// Example using switch statement
switch (type) {
case "walk":
case "bicycle":
return "Back Load";
case "motorcycle":
case "car":
return "Main Load";
}
// Example using a Map object
const vehicleLoadMap = {
walk: "Back Load",
bicycle: "Back Load",
motorcycle: "Main Load",
car: "Main Load"
};
return vehicleLoadMap[type];
Defining Event Handlers
Define event handlers outside of component body
This practice keeps the component body clean and improves readability.
Strategies for Memoization
Apply memoization judiciously
- Consider wrapping frequently re-rendered or seldom-changing props components with
React.memo
. - Memoization can enhance performance but may introduce overhead if misused, so choose your scenarios wisely.
Utilizing String Literal Types
Prefer string literal types over enums for type safety without redundancy
This approach ensures type safety while avoiding unnecessary code.
// Not recommended
const ALERT_TYPE = {
INFO: "INFO",
SUCCESS: "SUCCESS",
WARNING: "WARNING",
} as const;
// Recommended
type AlertType = "INFO" | "SUCCESS" | "WARNING";
Applying CSS
Use clsx
to manage class names based on conditions
// Example using `clsx`
import clsx from 'clsx';
<div className={clsx([styles.someStyle, isFoo && styles.fooStyle])}>
Text here
</div>
Specifying Values for Props
Follow a unified naming convention for passing props
This ensures the purpose of props is clear, facilitating data passing between components.
// Naming example for passing a collection
const TodoList: React.FC<{ items: TodoItem[] }> = ({ items }) => {...};
// Naming example for passing a single object
const TodoItemDetail: React.FC<{ item: TodoItem }> = ({ item }) => {...};
Final Thoughts
This guideline aims to uphold consistency and improve efficiency in front-end development using TypeScript and React. Adjustments may be necessary depending on project or team specifics, but striving for best practices is paramount. Through these conventions, we hope to enhance the readability and maintainability of our projects, facilitating smoother development processes and collaborations within the team.
Posted on March 18, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
March 18, 2024