JavaScript vs TypeScript - I built the same crypto tracker with both

Published: (December 27, 2025 at 06:00 PM EST)
5 min read
Source: Dev.to

Source: Dev.to

Both JavaScript and TypeScript achieve the same fundamental goal—making things happen in a browser—but the developer experience differs dramatically. To see which one feels better, I built the exact same Real‑Time Crypto Tracker with each language and compared the features, tooling, ecosystem, performance, and code.

Note – This isn’t a line‑by‑line coding tutorial. If you want to learn how to build these apps from scratch, subscribe to my free newsletter.

Setup

We start with Vite because create‑react‑app is dead and Vite scaffolds projects instantly.

LanguageCommand
JavaScriptnpm create vite@latest crypto-tracker-js -- --template react
TypeScriptnpm create vite@latest crypto-tracker-ts -- --template react-ts

Both commands are fast. Once the projects are opened in VS Code, the differences become obvious.

JavaScript project

  • package.json
  • vite.config.js
  • source files ending in .jsx

A lightweight feel—almost no configuration files.

TypeScript project

  • .tsx files
  • tsconfig.json and tsconfig.node.json

These JSON files define the project’s “constitution.” They let you enforce rules such as:

  • Allow implicit any?
  • Check for unused local variables?
  • Strictly check for nulls?

For beginners this can feel like “Configuration Hell,” while seasoned engineers see it as a safety blanket.

Structure

The core difference isn’t just syntax; it’s when you catch mistakes. JavaScript is dynamically typed, TypeScript is statically typed.

The Coin component (JavaScript)

const CoinRow = ({ coin }) => {
  return (
    <div>
      <h3>{coin.name}</h3>
      <p>${coin.current_price}</p>
    </div>
  );
};

In JavaScript the component relies on memory of the API shape. A typo like coin.price won’t raise an error until runtime, leading to guess‑and‑check debugging.

The Coin interface (TypeScript)

export interface Coin {
  id: string;
  symbol: string;
  name: string;
  image: string;
  current_price: number;
  high_24h: number;
  low_24h: number;
}
import type { Coin } from "./types";

interface Props {
  coin: Coin;
}

const CoinRow = ({ coin }: Props) => {
  return (
    <div>
      {/* IDE now shows a dropdown after typing "coin." */}
      <p>{coin.current_price}</p>
    </div>
  );
};

The editor instantly flags coin.price as an error:

Property ‘price’ does not exist on type ‘Coin’.

Data

export const fetchCoins = async () => {
  const res = await fetch("https://api.coingecko.com/...");
  return res.json();
};

JavaScript version (dangerous)

// No type safety – everything is `any`
export const fetchData = async (url) => {
  const res = await fetch(url);
  return res.json(); // (url: string): Promise => {
  // const res = await fetch(url);
  // return (await res.json()) as T;
};

The caller decides the shape:

interface Coin {
  id: string;
  symbol: string;
  name: string;
  image: string;
  current_price: number;
  high_24h: number;
  low_24h: number;
}

const coins = await fetchData("https://api.coingecko.com/...");

If the API changes, TypeScript will catch mismatches at compile time.

TL;DR

AspectJavaScriptTypeScript
SetupMinimal config, quick startExtra config (tsconfig.*) but provides safety
Developer experienceFast, but prone to runtime bugsIDE assistance, compile‑time checks
ScalabilityWorks for small demosIdeal for medium‑to‑large codebases
Learning curveLowHigher (type system, generics)
When to choosePrototyping, quick hacks, teams comfortable with runtime debuggingProjects where maintainability, refactoring, and team consistency matter

Generics

In TypeScript we can make the fetch function reusable:

export async function fetchData<T>(url: string): Promise<T> {
  const res = await fetch(url);
  if (!res.ok) {
    throw new Error('Network response was not ok');
  }
  const data = await res.json();
  return data as T;
}

The generic T lets the same function return Coin, user profiles, or any other shape—while keeping strict typing. However, as T is a lie to the compiler; runtime validation (e.g., with Zod) is still needed to guard against malformed API responses.

Trap

Storing fetched data in React state:

const [coins, setCoins] = useState([]);
  • In JavaScript the array can hold anything, which may lead to accidental type mixing.
  • In TypeScript the inferred type is usually fine, but you might need to be explicit:
const [coins, setCoins] = useState<Coin[]>([]);

Using any (e.g., useState<any[]>([])) disables type safety and spreads the problem throughout the codebase—like a paper seatbelt.

Refactoring

Changing a property name across the codebase is painless with TypeScript.

JavaScript

A manual “Find and Replace” risks touching unrelated occurrences (CSS classes, comments, etc.).

TypeScript

Rename the property in the interface (imageimageUrl) and the IDE updates only the relevant type references, leaving unrelated code untouched.

Performance

TypeScript must be compiled to JavaScript, but the runtime performance is identical.

  • Development: Vite uses esbuild to strip types on the fly; hot‑module replacement remains fast.
  • Production: tsc checks every line; the build fails on the first type error, preventing broken code from reaching users.

Thus, TypeScript doesn’t slow the app down, and it can speed up the development cycle over time.

Verdict

JavaScript

  • Great for hackathons, quick prototypes, and solo projects.
  • Low friction, but runtime bugs are more common.

TypeScript

  • Requires upfront effort (interfaces, config).
  • Pays off for larger, maintainable codebases with multiple collaborators.
  • Enables safe refactoring and self‑documenting code.

Bottom line: Choose JavaScript for fast experiments; choose TypeScript for anything that needs to scale, stay maintainable, and survive refactoring.

team members—TypeScript becomes the only thing keeping your sanity intact.
The ability to refactor instantly, the elimination of entire classes of bugs, and the self‑documenting nature of the code make it the superior choice for any serious application.

If you are looking to get hired in the industry today, TypeScript is not optional. It has won the war for attention.

So, stick with JavaScript if you want to feel like a cowboy. But learn TypeScript if you want to be an engineer.

If you want to see me suffer through building another app in the two programming languages or frameworks of your choice, then hit that subscribe button and let me know in the comments. Thanks for watching, and I will see you in the next one.

Back to Blog

Related posts

Read more »

Splice a Fibre

It's interactive, try and splice one! Written in react, it's moderately heavy and not entirely mobile optimised. Comments URL: https://news.ycombinator.com/item...

🎮 Retro Hangman '95 Using KIRO

!Cover image for 🎮 Retro Hangman '95 Using KIROhttps://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-t...

JavaScript

Key Trends - Innovation in runtimes: Deno’s latest release introduces a new tool dx for running NPM & JSR binaries, improving compatibility and developer workf...