TypeScript Surpassed JavaScript in 2025: How This Affects Your Developer Career
Hello HaWkers, a historic change happened: TypeScript surpassed JavaScript as the most used language on GitHub in 2025, breaking a hegemony of more than 10 years. Data shows that 65% of developers already use TypeScript in their projects, and this number only grows.
If you are still reluctant to learn TypeScript, thinking it is "just JavaScript with types," you are missing one of the most important transitions in web development history. Let's understand why TypeScript became essential, its real benefits, and how you can master it now.
The Meteoric Rise of TypeScript
TypeScript is no longer "that Microsoft thing." It is the dominant language of the modern JavaScript ecosystem:
// TypeScript adoption evolution
const adoptionTimeline = {
2012: 'Launch (Microsoft)',
2015: '5% of projects',
2018: '15% of projects',
2020: '35% of projects',
2023: '55% of projects',
2025: '65%+ of projects (SURPASSED JAVASCRIPT!)'
};
// Frameworks that adopted TypeScript as default
const frameworksTypeScriptFirst = [
'Angular (from the start)',
'Nest.js',
'Next.js (recommended)',
'Remix',
'Nuxt 3',
'SvelteKit',
'Astro',
'tRPC',
'Prisma'
// And practically every modern framework
];Why this explosion?
- Bug prevention: 15-20% of bugs are detected by TypeScript compiler
- Productivity: Powerful autocomplete and IntelliSense
- Safe refactoring: Structural changes without fear
- Living documentation: Types serve as always-updated documentation
- Scalability: Large projects become manageable
JavaScript vs TypeScript: The Difference in Practice
Let's see real examples of why TypeScript makes a difference:
Example 1: Avoiding Classic Bugs
// JavaScript: Silent bug waiting to happen
function calculateDiscount(price, discount) {
return price - (price * discount / 100);
}
calculateDiscount(100, "50"); // ❌ Result: NaN (bug!)
calculateDiscount(100); // ❌ Result: NaN (forgot argument!)
calculateDiscount("100", 50); // ❌ Result: weird string// TypeScript: Errors detected at compile time
function calculateDiscount(price: number, discount: number): number {
return price - (price * discount / 100);
}
calculateDiscount(100, "50"); // ❌ ERROR: Argument of type 'string' is not assignable
calculateDiscount(100); // ❌ ERROR: Expected 2 arguments, but got 1
calculateDiscount("100", 50); // ❌ ERROR: Argument of type 'string' is not assignable
calculateDiscount(100, 50); // ✅ OK: 50Example 2: Safe Refactoring
// JavaScript: Refactoring is dangerous
// users.js
const users = [
{ id: 1, name: "Jeff", email: "jeff@example.com" }
];
// You decide to change 'email' to 'emailAddress'
const users = [
{ id: 1, name: "Jeff", emailAddress: "jeff@example.com" }
];
// components/UserCard.js
function UserCard({ user }) {
return <div>{user.email}</div>; // ❌ BUG! Now it's undefined
}
// You don't know it broke until running in browser// TypeScript: Safe refactoring
interface User {
id: number;
name: string;
emailAddress: string; // Changed from 'email' to 'emailAddress'
}
const users: User[] = [
{ id: 1, name: "Jeff", emailAddress: "jeff@example.com" }
];
// components/UserCard.tsx
function UserCard({ user }: { user: User }) {
return <div>{user.email}</div>; // ❌ ERROR: Property 'email' does not exist on type 'User'
}
// TypeScript warns you IMMEDIATELY of all places that need to change
Advanced TypeScript Features
TypeScript goes far beyond "adding types." Advanced features transform how you write code:
1. Generics: Reusability with Type Safety
// Without Generics: Duplicated code or lost types
function getFirstElement(arr: any[]): any {
return arr[0]; // ❌ Lost type information
}
const firstNumber = getFirstElement([1, 2, 3]); // type: any
const firstString = getFirstElement(['a', 'b', 'c']); // type: any
// With Generics: Type preserved
function getFirstElement<T>(arr: T[]): T {
return arr[0];
}
const firstNumber = getFirstElement([1, 2, 3]); // type: number ✅
const firstString = getFirstElement(['a', 'b', 'c']); // type: string ✅
// Generics in interfaces
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
type UserResponse = ApiResponse<User>;
type ProductResponse = ApiResponse<Product[]>;
// Now response.data is correctly typed in each case!2. Union Types and Type Guards
// Union Types: Value can be of multiple types
type Status = 'loading' | 'success' | 'error';
function handleStatus(status: Status) {
if (status === 'loading') {
// TypeScript knows that here status === 'loading'
}
// if (status === 'pending') {} // ❌ ERROR: Not one of the allowed values
}
// Type Guards: Smart narrowing
type Response = { success: true; data: string } | { success: false; error: string };
function processResponse(response: Response) {
if (response.success) {
console.log(response.data); // ✅ TypeScript knows 'data' exists here
} else {
console.log(response.error); // ✅ TypeScript knows 'error' exists here
}
}3. Utility Types: Powerful Transformations
interface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
// Partial: Makes all properties optional
type UpdateUser = Partial<User>;
// = { id?: number; name?: string; email?: string; ... }
// Omit: Removes specific properties
type PublicUser = Omit<User, 'password'>;
// = { id: number; name: string; email: string; createdAt: Date }
// Pick: Selects only specific properties
type UserCredentials = Pick<User, 'email' | 'password'>;
// = { email: string; password: string }
// Required: Makes all properties required
type CompleteUser = Required<Partial<User>>;
// Readonly: Makes everything read-only
type ImmutableUser = Readonly<User>;
// Record: Creates object with typed keys and values
type UsersByRole = Record<'admin' | 'user' | 'guest', User[]>;
// = { admin: User[]; user: User[]; guest: User[] }
TypeScript and Backend Development
TypeScript is not just for frontend. Node.js + TypeScript is the dominant combination in modern backend:
// Nest.js: TypeScript-first backend framework
import { Controller, Get, Post, Body, Param } from '@nestjs/common';
import { UsersService } from './users.service';
import { CreateUserDto } from './dto/create-user.dto';
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Get()
async findAll(): Promise<User[]> {
return this.usersService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: string): Promise<User> {
return this.usersService.findOne(+id);
}
@Post()
async create(@Body() createUserDto: CreateUserDto): Promise<User> {
return this.usersService.create(createUserDto);
}
}
// DTOs: Automatic validation with types
export class CreateUserDto {
@IsString()
@IsNotEmpty()
name: string;
@IsEmail()
email: string;
@IsString()
@MinLength(8)
password: string;
}tRPC: End-to-End TypeScript APIs
// tRPC: Shared types between backend and frontend
// server/router.ts
import { z } from 'zod';
import { router, publicProcedure } from './trpc';
export const appRouter = router({
getUser: publicProcedure
.input(z.object({ id: z.number() }))
.query(async ({ input }) => {
return db.user.findUnique({ where: { id: input.id } });
}),
createUser: publicProcedure
.input(z.object({
name: z.string(),
email: z.string().email(),
}))
.mutation(async ({ input }) => {
return db.user.create({ data: input });
}),
});
export type AppRouter = typeof appRouter;// client/app.tsx
import { createTRPCReact } from '@trpc/react-query';
import type { AppRouter } from '../server/router';
const trpc = createTRPCReact<AppRouter>();
function UserProfile({ userId }: { userId: number }) {
// Full autocomplete! End-to-end types!
const { data: user } = trpc.getUser.useQuery({ id: userId });
return <div>{user?.name}</div>;
// TypeScript knows 'user' can be undefined
// TypeScript knows 'user.name' is string
}
TypeScript in the Job Market
The numbers are clear: TypeScript is essential for career:
const jobMarket2025 = {
jobsRequiringTypeScript: '78% of frontend positions',
salaryDifference: '+15-25% compared to pure JS',
topCompanies: [
'Google',
'Microsoft',
'Amazon',
'Meta',
'Netflix',
'Airbnb',
'Uber',
'Spotify'
// All use TypeScript
],
frameworks: {
react: 'TypeScript recommended',
angular: 'TypeScript mandatory',
vue: 'TypeScript full integration',
svelte: 'TypeScript natively supported'
}
};Jobs requiring TypeScript offer salaries 15-25% higher than pure JavaScript equivalents.
How to Migrate from JavaScript to TypeScript
Gradual migration is possible and recommended:
Step 1: Add TypeScript to Project
# Install TypeScript
npm install --save-dev typescript @types/node
# Create tsconfig.json
npx tsc --init// tsconfig.json - Initial permissive configuration
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"jsx": "react-jsx",
"strict": false, // Start permissive
"esModuleInterop": true,
"skipLibCheck": true,
"allowJs": true, // IMPORTANT: Allows .js and .ts together
"checkJs": false, // Don't check .js initially
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}Step 2: Rename Files Gradually
# Start with new/simple files
mv src/utils/formatters.js src/utils/formatters.ts
# Add types gradually
mv src/components/Button.jsx src/components/Button.tsxStep 3: Add Types Progressively
// Stage 1: Function without types (JavaScript)
function calculateTotal(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Stage 2: Add basic types
function calculateTotal(items: any[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// Stage 3: Specific types
interface Item {
id: number;
name: string;
price: number;
}
function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}Step 4: Enable Strict Mode Gradually
// tsconfig.json - Increase rigor gradually
{
"compilerOptions": {
"strict": true, // Enable after basic migration
// OR enable rules individually:
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitThis": true,
"alwaysStrict": true
}
}
Essential Tools of the TypeScript Ecosystem
// Zod: Runtime validation with type inference
import { z } from 'zod';
const UserSchema = z.object({
name: z.string(),
email: z.string().email(),
age: z.number().min(18)
});
type User = z.infer<typeof UserSchema>;
// Type: { name: string; email: string; age: number }
const user = UserSchema.parse(unknownData); // Validates at runtime!
// Type-fest: Advanced utility types
import type { PartialDeep, ReadonlyDeep, Merge } from 'type-fest';
// ts-node: Run TypeScript directly (Node.js 23.6+ doesn't need it!)
npx ts-node script.ts
// tsc-watch: Watch mode with hooks
npx tsc-watch --onSuccess "node dist/index.js"Why TypeScript Became Essential
The answer is simple: TypeScript solves real problems:
- Bugs detected before running: 15-20% of bugs caught by compiler
- Increased productivity: Autocomplete reduces development time
- Confident refactoring: Structural changes without fear
- Improved collaboration: Types serve as contract between developers
- Updated documentation: Types never lie, comments do
// Types as living documentation
interface PaymentProcessor {
/**
* Process payment and return transaction ID
* @throws {InsufficientFundsError} When balance is too low
* @throws {InvalidCardError} When card is invalid
*/
processPayment(amount: number, card: CreditCard): Promise<string>;
}
// When implementing, TypeScript forces you to follow the contract
class StripeProcessor implements PaymentProcessor {
async processPayment(amount: number, card: CreditCard): Promise<string> {
// Implementation here
// TypeScript ensures correct signature
}
}If you want to understand more about the future of JavaScript/TypeScript development, I recommend reading: Node.js Now Runs TypeScript Natively where we explore the most recent native integration.
Let's go! 🦅
💻 Master TypeScript and Accelerate Your Career
This article showed why TypeScript became essential, but mastering solid JavaScript is the first step before TypeScript.
Invest in Your Future
I have prepared complete material for you to master JavaScript, the foundation for TypeScript:
Payment options:
- $4.90 (single payment)

