Frontend Development 14 min read

Why Use TypeScript? Benefits, Setup, and Type Definitions for React Development

This article explains the drawbacks of weakly‑typed JavaScript, outlines the advantages of adopting TypeScript, and provides practical guidance on configuring ESLint, Prettier, tsconfig, and React component typings—including hooks, event handling, and generic utilities—to improve code quality and developer productivity.

ByteDance ADFE Team
ByteDance ADFE Team
ByteDance ADFE Team
Why Use TypeScript? Benefits, Setup, and Type Definitions for React Development

In everyday front‑end development, JavaScript’s weak typing leads to pain points such as unclear component/function parameters, difficult data‑flow tracing, ambiguous backend API contracts, and costly refactoring when dependencies change.

TypeScript was created to address these issues by allowing explicit type definitions for components, functions, and API contracts, which serve as living documentation, enable static analysis, and improve IDE assistance.

The benefits include early error detection, clearer data flow, stronger IDE autocomplete, and a robust type system, while the costs involve learning effort and ongoing type maintenance.

TypeScript in React

The recommended development environment combines ESLint, Prettier, and the TypeScript Playground for React. ESLint uses @typescript-eslint/eslint-plugin and @typescript-eslint/parser to enforce rules, while Prettier ensures consistent code formatting.

{
  "singleQuote": true,
  "trailingComma": "es5",
  "printWidth": 80,
  "semi": true,
  "tabWidth": 4,
  "useTabs": false
}

VSCode workspace settings can be adjusted to automatically fix .ts and .tsx files:

{
  "eslint.validate": ["typescript", "typescriptreact"]
}

The tsconfig.json file should enable strict type checking and useful compiler options:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "allowJs": true,
    "checkJs": true,
    "jsx": "preserve",
    "declaration": true,
    "sourceMap": true,
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "baseUrl": "./",
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

React Component Type Declarations

Class components use React.Component<P, S> or React.PureComponent<P, S, SS> , where P is Props, S is State, and SS is the snapshot type. Function components are declared with React.FunctionComponent<Props> (or React.FC ), which already includes children typing.

// Stateless component example
interface IProps {
  onClick(event: MouseEvent
) => void;
}
const Button: React.SFC
= ({ onClick, children }) => {
  return
{children}
;
};

Understanding the differences between JSX.Element , ReactNode , and ReactElement helps define return types for components.

React Hooks

Common hooks such as useState , useEffect , useRef , useImperativeHandle , useReducer , and custom hooks are illustrated, with notes on proper typing (e.g., useRef<HTMLInputElement>(null) vs. useRef<HTMLInputElement | null>(null) ).

// Correct useEffect pattern
useEffect(() => {
  const fetchUser = async () => {
    const user = await getUser();
    setUser(user);
  };
  fetchUser();
}, []);

Event Handling Types

React provides generic event types like React.ChangeEvent<HTMLInputElement> and handler interfaces such as MouseEventHandler<HTMLDivElement> . Using these types simplifies function signatures.

interface IProps {
  onClick: MouseEventHandler
;
  onChange: ChangeEventHandler
;
}

Promise Types

Async functions return Promise<T> . Defining a response interface and annotating the return type ensures proper type inference when chaining .then .

interface IResponse
{
  message: string;
  result: T;
  success: boolean;
}
async function getResponse(): Promise
> {
  return { message: '获取成功', result: [1, 2, 3], success: true };
}
getResponse().then(response => console.log(response.result));

Practical Tips

Prefer interface for object shapes that may be merged; use type for unions, tuples, and mapped types.

Leverage keyof , indexed access types, and conditional types ( extends , infer ) for generic utilities.

Use typeof to capture the type of a concrete value.

Utility generic examples include custom Record , Partial , Required , Readonly , Pick , Omit , and conditional types for type filtering and transformation.

frontendTypeScriptReactgenericsHooksESLintPrettier
ByteDance ADFE Team
Written by

ByteDance ADFE Team

Official account of ByteDance Advertising Frontend Team

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.