Typescript Tutorial ChatGPT
Typescript Tutorial ChatGPT
Introduction
Why TypeScript?
The Evolution of JavaScript and the Need for TypeScript
Setting Up Your Environment
Basic Syntax and Concepts
Conclusion
Best Practices for TypeScript
Resources for Further Learning
Final Thoughts
Introduction
Why TypeScript?
TypeScript is a powerful, statically typed superset of JavaScript that brings the power of static
typing and object-oriented programming to the world of JavaScript development. As JavaScript
projects grow in size and complexity, maintaining and debugging code becomes more
challenging. This is where TypeScript shines. It helps developers catch errors early, improves
code quality, and enhances the overall development experience.
Step 1: Install Node.js Download and install Node.js from the official website nodejs.org.
Node.js comes with npm, which will be used to install TypeScript and other dependencies.
Step 2: Install TypeScript Open your terminal and run the following command to install
TypeScript globally:
Step 3: Verify the Installation After installation, verify that TypeScript is installed by running:
tsc --version
Step 4: Set Up Visual Studio Code Download and install Visual Studio Code from
code.visualstudio.com. It's a powerful code editor with excellent TypeScript support.
tsc hello.ts
This will generate a hello.js file. You can run this file with Node.js:
node hello.js
Interfaces
Interfaces in TypeScript are a powerful way to define contracts within your code. They can define
the shape of an object, ensuring that an object meets certain criteria.
Defining Interfaces
printUser(user);
Optional Properties
interface User {
name: string;
age?: number;
}
Classes
Classes in TypeScript provide a way to define blueprints for creating objects with specific
properties and methods.
Defining a Class
greet(): string {
return `Hello, my name is ${this.name}`;
}
}
Inheritance
describe(): string {
return `${this.name} works as a ${this.position}`;
}
}
Implementing Interfaces
Classes can implement interfaces to ensure they adhere to a specific contract:
interface Drivable {
startEngine(): void;
stopEngine(): void;
}
stopEngine(): void {
console.log('Engine stopped');
}
}
Conclusion
In this chapter, we've explored the basics of interfaces and classes in TypeScript. These powerful
features help you define clear contracts and reusable blueprints for your objects, making your
code more robust and maintainable. In the next chapter, we'll dive into advanced types and how
they can further enhance your TypeScript code.
Sure, let's continue by expanding on the next chapters to provide more content and structure.
I'll extend the previous chapters and introduce more chapters to create a comprehensive
learning experience for TypeScript.
Union Types
Union types are used when a value can be one of several types:
printId(101);
printId("202");
Intersection Types
interface Person {
name: string;
}
interface Employee {
employeeId: number;
}
Type Guards
Type guards allow you to narrow down the type within a union type using specific checks.
Using typeof
class Car {
drive() {
console.log('Driving a car');
}
}
class Truck {
tow() {
console.log('Towing a truck');
}
}
Literal Types
move('north');
Type Aliases
type User = {
name: string;
age: number;
};
Chapter 7: Generics
Generics provide a way to create reusable components that work with any data type.
Generic Functions
Generic functions allow you to write functions that can work with any type:
console.log(identity<number>(10));
console.log(identity<string>('Hello'));
Generic Classes
Generic classes work similarly to generic functions:
class Box<T> {
contents: T;
constructor(contents: T) {
this.contents = contents;
}
getContents(): T {
return this.contents;
}
}
Generic Constraints
Generic constraints allow you to limit the kinds of types that a generic type parameter can
accept:
interface Lengthwise {
length: number;
}
logLength('Hello');
logLength([1, 2, 3]);
Chapter 8: Decorators
Decorators provide a way to add metadata to classes, methods, properties, and parameters.
Method Decorators
Method decorators can be used to modify or annotate methods:
function log(target: any, propertyName: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyName} with arguments: ${args}`);
return originalMethod.apply(this, args);
}
}
class Calculator {
@log
add(a: number, b: number): number {
return a + b;
}
}
Class Decorators
Class decorators can be used to add metadata to classes:
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return `Hello, ${this.greeting}`;
}
}
Property Decorators
Property decorators can be used to add metadata to properties:
function logProperty(target: any, key: string) {
let value = target[key];
Object.defineProperty(target, key, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
class Person {
@logProperty
name: string;
constructor(name: string) {
this.name = name;
}
}
Namespaces
Namespaces are used to organize code into logical groups and prevent name collisions.
Defining and Using Namespaces
namespace Utility {
export function log(message: string): void {
console.log(message);
}
Modules
Modules in TypeScript align with the ES6 module system and are used to organize code into
separate files and modules.
File: math.ts
File: main.ts
console.log(add(10, 5));
console.log(subtract(10, 5));
Functional Components
interface Props {
message: string;
}
Class Components
import React, { Component } from 'react';
interface Props {
message: string;
}
interface UserContextType {
name: string;
age: number;
}
Using Hooks
import React, { useState } from 'react';
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
Absolutely, let's continue with the advanced project chapters. We'll dive into building a REST API
with TypeScript and Node.js, creating real-time applications with Socket.io, working with
GraphQL, and building a full-stack application.
mkdir rest-api
cd rest-api
npm init -y
src/
models/
user.ts
controllers/
userController.ts
routes/
userRoutes.ts
app.ts
server.ts
File: src/models/user.ts
import mongoose, { Document, Schema } from 'mongoose';
File: src/controllers/userController.ts
export const createUser = async (req: Request, res: Response): Promise<void> => {
try {
const { name, email, password } = req.body;
const user: IUser = new User({ name, email, password });
await user.save();
res.status(201).json(user);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
Setting Up Routes
File: src/routes/userRoutes.ts
import { Router } from 'express';
import { createUser } from '../controllers/userController';
router.post('/users', createUser);
app.use(bodyParser.json());
app.use('/api', userRoutes);
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
"scripts": {
"start": "ts-node src/server.ts",
"dev": "nodemon src/server.ts"
}
You now have a basic REST API setup with TypeScript and Node.js.
mkdir real-time-app
cd real-time-app
npm init -y
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules"]
}
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
document.getElementById('sendButton').addEventListener('click', () => {
const messageInput = document.getElementById('messageInput');
const message = messageInput.value;
socket.emit('message', message);
messageInput.value = '';
});
});
</script>
</head>
<body>
<h1>Real-Time Chat</h1>
<ul id="messages"></ul>
<input id="messageInput" type="text" placeholder="Type a message" />
<button id="sendButton">Send</button>
</body>
</html>
Serve the static file from your Express server: Update src/server.ts
app.use(express.static('src'));
Start the server and open http://localhost:3000 in your browser to see the real-time chat
application in action.
mkdir graphql-app
cd graphql-app
npm init -y
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules"]
}
File: src/server.ts
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: root,
graphiql: true
}));
mkdir full-stack-app
cd full-stack-app
mkdir server
cd server
npm init -y
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true
},
"include": ["src"],
"exclude": ["node_modules"]
}
File: src/controllers/authController.ts
import { Request, Response } from 'express';
import User, { IUser } from '../models/user';
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
export const register = async (req: Request, res: Response): Promise<void> => {
try {
const { name, email, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const user: IUser = new User({ name, email, password: hashedPassword });
await user.save();
res.status(201).json({ message: 'User registered successfully' });
} catch (error) {
res.status(500).json({ message: error.message });
}
};
export const login = async (req: Request, res: Response): Promise<void> => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user || !await bcrypt.compare(password, user.password)) {
res.status(401).json({ message: 'Invalid credentials' });
return;
}
const token = jwt.sign({ id: user._id }, SECRET_KEY, { expiresIn: '1h' });
res.status(200).json({ token });
} catch (error) {
res.status(500).json({ message: error.message });
}
};
File: src/routes/authRoutes.ts
import { Router } from 'express';
import { register, login } from '../controllers/authController';
router.post('/register', register);
router.post('/login', login);
File: src/app.ts
app.use(bodyParser.json());
app.use('/api/auth', authRoutes);
File: src/server.ts
import app from './app';
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
"scripts": {
"start": "ts-node src/server.ts",
"dev": "nodemon src/server.ts"
}
Install the necessary dependencies for making HTTP requests and managing authentication:
Setting Up Authentication
File: src/App.tsx
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Register from './components/Register';
import Login from './components/Login';
File: src/components/Register.tsx
import React, { useState } from 'react';
import axios from 'axios';
return (
<form onSubmit={handleSubmit}>
<div>
<label>Name</label>
<input type="text" value={name} onChange={(e) => setName(e.target.value)} />
</div>
<div>
<label>Email</label>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<label>Password</label>
<input type="password" value={password} onChange={(e) =>
setPassword(e.target.value)} />
</div>
<button type="submit">Register</button>
</form>
);
};
File: src/components/Login.tsx
import React, { useState } from 'react';
import axios from 'axios';
return (
<form onSubmit={handleSubmit}>
<div>
<label>Email</label>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)}
/>
</div>
<div>
<label>Password</label>
<input type="password" value={password} onChange={(e) =>
setPassword(e.target.value)} />
</div>
<button type="submit">Login</button>
</form>
);
};
"proxy": "http://localhost:5000"
Start the React development server:
npm start
Now you have a full-stack application with a TypeScript back-end and front-end, including user
registration and login functionality.