Website profiles · Technology insights · Alternatives

react-typescript-cheatsheet.netlify.app

A cheatsheet for developers using React with TypeScript

No paid content found
Visit website
Profile views 15 Outbound visits 19 Normal
React TypeScript Cheatsheet Full homepage screenshot

At a glance

Category
Development
Language
English
Paid-content signal
No paid content foundObserved
Registered
2018
Hosting
NetlifyInferred
HTTPS certificate trusted
PassedObserved
Last updated

Website review

This review may include AI-generated content and is not individually verified. Domain, certificate and other facts come from the observed data on this page.

What is React TypeScript Cheatsheet?

React TypeScript Cheatsheet is a free, community-maintained reference site for developers who write React components in TypeScript. Rather than teaching React or TypeScript from scratch, it answers the recurring "how do I type this?" questions you hit mid-project: props, hooks, refs, events, context, and common component patterns.

The site is organized into three rough layers:

  • Introduction — setup guidance for React with TypeScript across frameworks such as Next.js, Remix, Gatsby, and Expo.
  • Topic pages — typing component props, hooks, class components, defaultProps, forms and events, context, refs, portals, error boundaries, concurrent rendering, and reusable patterns.
  • API reference — focused notes on the @types/react types you reach for most, including ComponentProps, CSSProperties, ReactNode, and Ref.

Who it suits. It fits developers who already know React and are adding or deepening TypeScript, and teams standardizing how they type shared components. It is less useful as a first tutorial; if you have never written either technology, learn the basics first and keep this open as a lookup.

How it compares to alternatives. The official React docs cover typing at a conceptual level but stay framework-agnostic and relatively brief. React is the better starting point for how React works. TypeScript explains the type system itself, which matters when an error is about generics or narrowing rather than React. Total TypeScript leans toward paid, exercise-driven learning. This cheatsheet sits in the middle: quick, example-first answers without a course structure.

A concrete scenario. You are building a reusable <Select> and need to type a generic options prop plus the onChange handler. The Introduction and API reference sections are the places to look for ComponentProps and pattern examples, then adapt them to your own prop names.

Decision criterion. Use it when you want a copy-adaptable snippet in seconds. When you need to understand why a type behaves as it does, follow the pattern back to the underlying @types/react definition or the TypeScript handbook.

Next step. Open the popular-topics list, find the entry closest to your current blocker — hooks, forms and events, or forwardRef — and read that page before searching elsewhere.

How do I type React hooks like useState and useEffect in TypeScript?

Type React hooks by giving the hook an explicit type argument or by letting TypeScript infer it from the initial value, then typing the callback parameters in useEffect or handling the undefined case when a ref or DOM node may not exist yet.

useState

  • Let inference do the work when the initial value already describes the state: const [count, setCount] = useState(0) gives you number.
  • Reach for an explicit argument when the initial value is narrower than the state you want: useState<User | null>(null) lets you start empty and assign a user later.
  • If a value can be absent, include undefined or null in the type rather than relying on a cast. That forces you to handle the empty case at the point of use.
  • For arrays that start empty, type the element: useState<Item[]>([]), otherwise TypeScript may infer never[] and reject later pushes.

useEffect

  • The callback takes no arguments for a plain effect. Type the values you read inside it, not the callback itself.
  • The return value is either nothing or a cleanup function: return () => { ... }. TypeScript checks this shape for you.
  • When you touch the DOM, narrow the ref first: if (!node) return; before using node.scrollHeight or similar. This is the most common source of errors for people new to typed React.
  • Dependencies are inferred from what you reference. If you extract a function used in the effect, wrap it in useCallback so its identity is stable and the dependency list stays honest.

A quick comparison

Hook When inference is enough When to annotate
useState Initial value matches the final type State can be null/undefined, or starts as an empty array
useEffect Almost always Rarely; type the ref or the values you read
useRef Ref holds a simple mutable value Ref points at a DOM element: useRef<HTMLDivElement>(null)

A concrete scenario

You are building a search box that fetches results. You start with useState<Result[]>([]) so the list type is fixed before any data arrives, and a useState<string>('') for the query. In useEffect, you read the query, call the API, and return a cleanup that aborts the request. The abort controller lives in a useRef<AbortController | null>(null) so it survives re-renders without triggering them. Each of these annotations exists to close a specific gap that inference alone leaves open.

For a focused reference on the @types/react types you will reach for most, including ComponentProps, ReactNode and Ref, see React TypeScript Cheatsheet. If you want the official wording on hook rules and types, the React docs at React cover the runtime behaviour that these types describe.

How do I type function component props and defaultProps in TypeScript?

Type function component props by declaring an explicit props type and using it in the component signature. For defaults, prefer default parameter values in the function signature; defaultProps is legacy and behaves differently with TypeScript, especially for function components, so it is usually better to avoid it.

Function component props

Use a type or interface for the props object, then annotate the parameter. This gives you autocomplete, required/optional checking, and errors for unknown props.

type ButtonProps = {
  label: string;
  onClick?: () => void;
  disabled?: boolean;
};

function Button({ label, onClick, disabled = false }: ButtonProps) {
  return (
    <button onClick={onClick} disabled={disabled}>
      {label}
    </button>
  );
}

Key points:

  • label: string is required; omitting it is a type error.
  • onClick?: () => void is optional and may be undefined.
  • Destructuring with disabled = false gives a default value inside the component.
  • Do not type props as any; that removes the main benefit of using TypeScript with React.

Default values

The simplest and most type-safe approach is default parameter values:

type CardProps = {
  title: string;
  subtitle?: string;
  elevated?: boolean;
};

function Card({ title, subtitle = "No subtitle", elevated = false }: CardProps) {
  // subtitle is string, elevated is boolean
}

This keeps the call site clean and makes the default visible where the prop is used. The external prop type still allows subtitle to be omitted, because it is optional.

Why defaultProps is awkward

With function components, defaultProps is a legacy pattern. TypeScript often cannot infer that a prop with a default is non-optional inside the component, so you may still need to handle undefined or use extra type helpers. It also interacts poorly with newer React versions and function component types. For new code, use default parameters instead.

If you must use defaultProps, keep it on the component and be prepared to widen or narrow the props type carefully. The React TypeScript Cheatsheet covers defaultProps alongside typing component props, hooks, forms and events, context, refs, and reusable patterns, so it is a useful reference when you need the exact edge-case behavior.

Choosing between them

Approach Best for Trade-off
Default parameter values Most function components Defaults live in the function body; clear and type-safe
defaultProps Legacy class-style or older codebases Easier to misuse with TypeScript; can require extra typing
Optional props without defaults Props that may genuinely be absent You must handle undefined inside the component

Practical next step

Start with a type for props and default parameter values. If you are unsure how to type a more complex case, such as forwardRef, generic components, or event handlers, check the relevant sections in the React TypeScript Cheatsheet and compare its examples with the React types in your project.

How do I handle forms and events with TypeScript in React?

Typing forms and events in React comes down to three things: type the event handler's parameter, type the form's state, and let @types/react infer what it can. The React TypeScript Cheatsheet covers forms and events as a dedicated topic, alongside hooks, context, and refs.

The core pattern

For a controlled input, the handler receives a change event. The reliable approach is to type the parameter explicitly rather than relying on inference from an inline arrow:

const [email, setEmail] = useState("");

function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
  setEmail(e.target.value);
}

<input value={email} onChange={handleChange} />

ChangeEvent<HTMLInputElement> gives you e.target.value as a string. Swap the generic for HTMLTextAreaElement or HTMLSelectElement as needed.

Typing the submit handler

Use React.FormEvent<HTMLFormElement> and call preventDefault():

function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
  e.preventDefault();
  // validate and send
}

Event types worth knowing

Event Type
Input/select/textarea change ChangeEvent<HTMLInputElement> (or the matching element)
Form submit FormEvent<HTMLFormElement>
Button click MouseEvent<HTMLButtonElement>
Key press KeyboardEvent<HTMLInputElement>
Focus/blur FocusEvent<HTMLInputElement>

Practical trade-offs

  • Inline handlers: onChange={(e) => setEmail(e.target.value)} infers the type correctly, so you often need no annotation. Extracted named functions need the explicit type, which is why the cheatsheet-style pattern above annotates.
  • One state object vs. many: a single useState({ email: "", name: "" }) keeps the submit logic tidy but you must spread the previous state on every update. Separate useState calls are simpler to type and update.
  • Uncontrolled forms: reading values via FormData on submit avoids per-keystroke state entirely, at the cost of losing live validation. Type the entries with String(formData.get("email")) since get returns FormDataEntryValue | null.

Next step

If you're starting fresh, decide first whether the form is controlled or uncontrolled; that choice determines how much event typing you'll write. Then check the cheatsheet's forms and events section for the specific element types you're using, and its "useful patterns by use case" section if you need a reusable typed field component.

How do I use forwardRef and refs with TypeScript in React?

Use forwardRef when a parent needs to pass a ref down to a DOM node or component inside a child function component. In TypeScript, the key is to give the ref a precise element type and let forwardRef infer the props.

import { forwardRef, useRef, useImperativeHandle } from "react";

type InputProps = { label: string };

const TextInput = forwardRef<HTMLInputElement, InputProps>(
  ({ label }, ref) => (
    <label>
      {label}
      <input ref={ref} />
    </label>
  )
);

function Form() {
  const inputRef = useRef<HTMLInputElement>(null);

  return (
    <>
      <TextInput label="Email" ref={inputRef} />
      <button onClick={() => inputRef.current?.focus()}>Focus</button>
    </>
  );
}

The first type argument is the element or handle the ref points to; the second is the component's own props. That ordering is the most common source of confusion.

Common patterns

  • DOM refs: forwardRef<HTMLInputElement, Props> when the ref lands on an <input>. Swap in HTMLDivElement, HTMLButtonElement, etc. as needed.
  • useRef with no initial value: useRef<HTMLInputElement>(null) yields RefObject<HTMLInputElement>, whose .current may be null. Guard with ?. before calling methods.
  • useRef with an initial value: useRef<number>(0) yields a mutable ref where .current is always a number.
  • Imperative handles: when you want to expose methods rather than a DOM node, use useImperativeHandle and type the ref as your handle interface.
  • Ref as a prop (React 19+): newer React versions let function components accept ref directly as a prop, so forwardRef is no longer required there. If you are on an older React version, keep using forwardRef.

forwardRef vs. ref-as-prop

Situation Recommended approach
React 18 or earlier forwardRef<Element, Props>
React 19+ ref as a normal prop, typed as Ref<Element>
Exposing custom methods useImperativeHandle with a handle type
Passing a ref through several layers forwardRef at each layer, or ref-as-prop in React 19+

Practical next step

If you are unsure which element type to use, hover the JSX element in your editor: the DOM type is usually shown there. For example, hovering <input> reveals HTMLInputElement, which is exactly what the first forwardRef type argument expects.

The React TypeScript Cheatsheet covers forwardRef, refs, ComponentProps, and related patterns in its API reference and "Useful patterns" sections, which is a reasonable place to check the exact signatures once you know which element or handle you are targeting.

How do I type React context and error boundaries in TypeScript?

For both React context and error boundaries, TypeScript's main job is to describe the values that flow through React's runtime, not to change how React behaves. The React TypeScript Cheatsheet treats context, refs, and error boundaries as separate "popular topics," which is a sensible split: each has its own typing shape and pitfalls.

Typing React context

Context has two distinct types: the shape of the value and the type of the context object itself.

  • Create the context with a deliberate default. createContext infers from its argument, so pass a real default when one exists; otherwise use a nullable default and handle the null case at the consumer.
  • A common pattern is a null default plus a custom hook. Create the context with null (or undefined), then write a useContext wrapper that throws when the value is missing. Consumers get a non-nullable value without a ! assertion at every call site.
  • Keep the provider value stable. The type doesn't prevent a new object being created on every render; memoize the value if consumers re-render too often.
  • Split contexts when update frequency differs. A state context and a dispatch context typed separately let components subscribe only to what they need.
  • Watch the generic inference. createContext<T>(default) gives you Context<T>; if you omit the generic, a too-narrow default can make later values fail to type-check.

A concrete scenario: a theme provider holding { theme: "light" | "dark"; toggle: () => void }. Type the context as that object, default to null, and expose a useTheme() hook that throws if called outside the provider. Every component then gets autocomplete on theme and toggle and a clear error if the provider is missing.

Typing error boundaries

Error boundaries must be class components, because componentDidCatch and getDerivedStateFromError have no hook equivalents.

  • Props are usually just children: React.ReactNode, plus any fallback or logging props you want to pass down.
  • State needs an hasError: boolean field (and optionally the caught error itself).
  • getDerivedStateFromError is static, takes the thrown value (typed unknown or Error) and returns the state update.
  • componentDidCatch receives (error: Error, errorInfo: React.ErrorInfo) and is where logging belongs.
  • Render either the fallback or children. The fallback can be a prop typed as React.ReactNode or a render function if it needs the error.

Practical detail: getDerivedStateFromError receives whatever was thrown, which is not guaranteed to be an Error. Typing it as unknown and normalizing inside is more honest than assuming Error.

If you want the project's own examples of these patterns, the cheatsheet's "Useful patterns by use case" section is the place to start; it is organized by scenario rather than by API, which suits readers who already know the React feature and just need the type signature.

Related questions

More questions →
What Can You Actually Do With a Free Hosted REST API Like ReqRes?

A free hosted REST API like ReqRes gives you a real HTTP endpoint you can call immediately—no signup, no local server, no database setup. You get predictable JSON responses for users, resources, login, and registration, which makes it useful for front-end demos, integration tests, learning HTTP clients, and prototyping. What it is not is a production backend for your app: the data is shared, resets periodically, and you don't control the schema. If you need persistent, private data with auth and logs, that's where an account-based backend or a commercial licence comes in.

What "free REST API for testing and prototyping" actually means

The phrase sounds vague, so it helps to separate two things people often conflate:

  • A mock/sample API — a public, hosted service with fixed or semi-fixed endpoints that return realistic-looking JSON. You don't own the data. It exists so you can point code at a URL and get a response.
  • A real backend you configure — a service where you define collections, schemas, authentication, and logging, and where your data persists and belongs to you.

ReqRes's landing page describes both: a free REST API for testing and prototyping with real responses and no signup, plus an option to build your own backend with collections, auth, and logs at app.reqres.in. Those are different products with different trade-offs. The free public endpoints are the "point and go" part; the account-based backend is the "own your data" part.

What you can do with the no-signup public endpoints

1. Front-end demos without a backend

If you're building a UI and need data to render, you can fetch from a public endpoint instead of hardcoding arrays. This keeps your demo code closer to real fetch logic:

async function loadUsers(page = 1) {
  const res = await fetch(`https://reqres.in/api/users?page=${page}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const { data, total, page: current } = await res.json();
  return { users: data, total, page: current };
}

You get pagination fields, a data array, and support metadata—enough to build list views, loading states, and empty states.

2. Integration and contract tests

You can assert that your HTTP layer handles status codes, headers, and JSON shapes correctly. Typical checks:

  • GET /api/users/2 returns 200 with a data object.
  • GET /api/users/23 returns 404 (a non-existent user).
  • POST /api/login with valid credentials returns a token; with missing fields returns 400.

This is useful for testing your client wrapper, retry logic, error handling, and serialization—without spinning up your own server.

3. Learning HTTP clients and tooling

If you're new to fetch, Axios, curl, Postman, or HTTPie, a hosted API is a low-friction target. You can practice:

  • Sending query parameters (?page=2, ?delay=3).
  • Setting headers and reading response headers.
  • Handling POST, PUT, PATCH, DELETE.
  • Observing status codes for success and failure.

4. Deliberate failure and latency testing

Endpoints that return 404 on purpose, or that accept a delay parameter, let you test how your app behaves when things go wrong or slow down. That's hard to do reliably against a happy-path local mock.

What the public endpoints are not good for

Use case Public sample endpoints Account-based backend
Persistent, private data No — shared and reset Yes
Custom schema/collections No Yes
Authentication you control Limited (demo login) Yes
Request logs and debugging No Yes
Production traffic Not intended Depends on plan/licence
Team collaboration No Yes

The key limitation: you don't own the data, and other people are hitting the same endpoints. Treat responses as illustrative, not authoritative.

When you'd move to an account-based backend

Consider app.reqres.in (collections, auth, logs) when any of these are true:

  • You need your own collections and fields, not the fixed demo schema.
  • You need data to persist between sessions and belong only to you.
  • You need real authentication flows you can rely on in a demo or internal tool.
  • You need request logs to debug what your client actually sent.
  • You're working with a team and need shared, stable endpoints.

The trade-off is setup and, eventually, cost. The public endpoints require none; the backend requires an account and configuration.

Where pricing and licensing become relevant

The site signals a commercial licence and an upgrade path (with Stripe as the payment platform), but specific prices, plan tiers, and limits aren't stated here—so don't assume numbers. What you can reason about:

  • Prototyping and learning → free public endpoints are usually enough.
  • Internal tools, demos for clients, or anything you don't want reset → an account-based backend is the natural next step.
  • Production or commercial use → check the licence terms and any paid plan, because "free for testing" and "free for commercial production" are not the same thing.

Before committing, read the current terms on the site rather than relying on secondhand summaries, since pricing and licence scope change.

A quick decision checklist

  1. Do you need data that persists and is private? If yes → account-based backend.
  2. Do you need a custom schema? If yes → account-based backend.
  3. Are you only testing HTTP behavior, UI rendering, or learning a client? If yes → free public endpoints.
  4. Will this touch real users or revenue? If yes → review the licence and any paid plan first.
  5. Do you need logs and team access? If yes → account-based backend.

If you answer "no" to 1, 2, 4, and 5, the free hosted API is likely all you need. If you answer "yes" to any of them, plan for the account-based path.

Website Overview

Identifiable technologies and additional version or configuration signals make the service easier to fingerprint, which may help targeted scanners narrow their checks. An established domain and managed infrastructure suggest continuity of operations and may support dependable delivery, although neither guarantees service quality.

Domain and Registration

Registered in 2018, this domain has about 8 years of history. That suggests continuity, although ownership and purpose may have changed. Transfer-protection status is present, helping reduce the risk of unauthorized domain transfers. The domain uses the common .app extension, which is not an independent safety signal.

DNS and Email

Nameservers are provided by NS1, indicating managed DNS hosting. CAA records restrict which certificate authorities are authorized to issue certificates. No CNAME was found; the observed records resolve directly to addresses. No MX record was found. A conventional explicit inbound-mail route is not configured. TXT records include verification markers for Google. Such markers may also remain after a service stops being used.

TLS and Certificates

The certificate includes the organization field Netlify, Inc. The certificate issuer is DigiCert Inc, a commercial certificate authority. The public key uses EC with 256 bits. The server supplied a complete certificate chain. The certificate is valid for about 396 days in total, with 168 days remaining.

HTTP and Browser Security

The response lacks these common security headers: CSP, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, clickjacking protection. No X-Powered-By header was found, reducing one common source of backend fingerprinting information. No obvious internal addresses or debug information were found in the headers. The Server header contains the custom value Netlify. No explicit CDN or WAF marker was found in the response headers.

Technology Stack Analysis

The public page identifies Docusaurus 3.10.1, Netlify, with exact versions exposed for 1 technologies. These details can narrow vulnerability checks, although exposure alone is not a vulnerability.

Search and Social Sharing

The Generator tag identifies Docusaurus v3.10.1, making the publishing system easier to fingerprint. Open Graph is partially configured; og:type is missing. Twitter Card metadata is configured. The page declares 2 language or regional alternatives using hreflang. The title has 27 characters, within a common display range.

Hosting and Email

DNSNS1
HostingNetlify
EmailUnknown
Approximate IP geolocation (inferred; a CDN or proxy may differ from the origin server) United States flagAshburn, Virginia, United States Inferred 18.208.88.157

Registration details

RDAP / WHOIS

RegistrarName.com, Inc.
Registered2018-05-08
Expires2031-05-08
Domain statusclient transfer prohibited
Nameserversdns1.p01.nsone.net、dns2.p01.nsone.net、dns3.p01.nsone.net、dns4.p01.nsone.net
DNSSECunsigned

DNS records

DNS

TypeNameValueTTLPriority
Areact-typescript-cheatsheet.netlify.app18.208.88.157120—
Areact-typescript-cheatsheet.netlify.app98.84.224.111120—
AAAAreact-typescript-cheatsheet.netlify.app2600:1f18:16e:df01::258311—
AAAAreact-typescript-cheatsheet.netlify.app2600:1f18:16e:df01::259311—
NSnetlify.appdns1.p01.nsone.net3600—
NSnetlify.appdns2.p01.nsone.net3600—
NSnetlify.appdns3.p01.nsone.net3600—
NSnetlify.appdns4.p01.nsone.net3600—
TXTnetlify.app_kvz3va36b5cudpl46gbej22cfyyw9081800—
TXTnetlify.appgoogle-site-verification=0KCpoJchrixypEMvtkzLtj6VMqMXKcuWS7j2jjjDcys1800—
TXTnetlify.appv=spf1 -all1800—
CAAnetlify.app128 iodef "mailto:[email protected]"1800—
CAAnetlify.app128 issue "digicert.com;account=2d83e9ac9b6776c3f215150f6ebceea8cefe3bc2e1fb5efffb1d71e200575226"1800—
DMARC_dmarc.netlify.appv=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1300—

TLS and certificates

TLS / SSL

AssessmentNormal configuration
Supported protocolsTLSv1.2、TLSv1.3
Negotiated protocolTLSv1.3
Certificate subject*.netlify.app
IssuerDigiCert Inc
Valid until2027-03-19T23:59 · Remaining when checked: 168 days
Verification detailsCertificate trust: Passed · Hostname match: Passed

HTTP response headers

HTTP

HeaderValue
content-typetext/html; charset=UTF-8
cache-controlpublic,max-age=0,must-revalidate
serverNetlify
strict-transport-securitymax-age=31536000; includeSubDomains; preload

Identified technologies

Docusaurus 3.10.1Netlify

Pages, Search and Sharing

Meta descriptionA cheatsheet for developers using React with TypeScript
Canonical URLhttps://react-typescript-cheatsheet.netlify.app/
LanguageEnglish (default)
Twitter Cardsummary_large_image

No robots.txt found

User reviews (0)

  • No reviews yet.