JavaScript vs TypeScript - I built the same crypto tracker with both
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.
| Language | Command |
|---|---|
| JavaScript | npm create vite@latest crypto-tracker-js -- --template react |
| TypeScript | npm 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.jsonvite.config.js- source files ending in
.jsx
A lightweight feel—almost no configuration files.
TypeScript project
.tsxfilestsconfig.jsonandtsconfig.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
| Aspect | JavaScript | TypeScript |
|---|---|---|
| Setup | Minimal config, quick start | Extra config (tsconfig.*) but provides safety |
| Developer experience | Fast, but prone to runtime bugs | IDE assistance, compile‑time checks |
| Scalability | Works for small demos | Ideal for medium‑to‑large codebases |
| Learning curve | Low | Higher (type system, generics) |
| When to choose | Prototyping, quick hacks, teams comfortable with runtime debugging | Projects 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 (image → imageUrl) 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
esbuildto strip types on the fly; hot‑module replacement remains fast. - Production:
tscchecks 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.