Skip to content

Commit 7412bfd

Browse files
committed
add exercise solutions
1 parent 6e0cd63 commit 7412bfd

File tree

27 files changed

+1363
-0
lines changed

27 files changed

+1363
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Exercise 1.1: Type annotations
2+
// Add/correct type annotations to all the variable and functions below.
3+
4+
const age: number = 25;
5+
const message: string = "Hello, world!";
6+
const isTrue: boolean = true;
7+
8+
function add(a: number, b: number): number {
9+
return a + b;
10+
}
11+
12+
function sayHello(name: string): string {
13+
return `Hello, ${name}!`;
14+
}
15+
16+
function isEven(n: number): boolean {
17+
return n % 2 === 0;
18+
}
19+
20+
function getAge(): number {
21+
return 25;
22+
}
23+
24+
// ignore the line below
25+
export {};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Exercise 10.1: Arrays, Records and Tuples
2+
3+
// 1. Create a type annotation for an array of numbers
4+
const scores: number[] = [75, 82, 90, 88, 95];
5+
6+
// 2. Create a type annotation for a tuple of [string, number, boolean]
7+
const userInfo: [string, number, boolean] = ["Alice", 28, true];
8+
9+
// 3. Create a type annotation for a record with string keys and number values
10+
const studentGrades: Record<string, number> = {
11+
Alice: 95,
12+
Bob: 87,
13+
Charlie: 92,
14+
};
15+
16+
// 4. Create a function that takes an array of numbers and returns their sum
17+
function sumScores(scores: readonly number[]) {
18+
return scores.reduce((sum, score) => sum + score, 0);
19+
}
20+
21+
// 5. Create a function that takes a tuple of [string, number] and returns a greeting
22+
function greetWithAge(info: [string, number]) {
23+
const [name, age] = info;
24+
return `Hello, ${name}! You are ${age} years old.`;
25+
}
26+
27+
// ignore the line below
28+
export {};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Exercise 12.1: Readonly types and "as const"
2+
3+
// 1. Create a readonly version of the following interface
4+
type User = {
5+
id: number;
6+
name: string;
7+
email: string;
8+
}
9+
10+
type ReadonlyUser = Readonly<User>;// Your implementation here
11+
12+
// 2. Use the readonly version to annotate the following object
13+
const alice: ReadonlyUser = {
14+
id: 1,
15+
name: "Alice",
16+
email: "alice@example.com"
17+
};
18+
19+
// 3. Create a readonly array of numbers
20+
const luckyNumbers: readonly number[] = [7, 13, 42, 99];
21+
22+
// 4. Use "as const" to create a readonly tuple of string literals
23+
const directions = ["North", "South", "East", "West"] as const;
24+
25+
// 5. Create a function that takes a readonly array of numbers and tries to modify it
26+
function doubleNumbers(numbers: readonly number[]) {
27+
// Try to modify the array (this should cause a type error)
28+
// numbers[0] = numbers[0] * 2;
29+
return numbers.map(n => n * 2);
30+
}
31+
32+
// 6. Modify the following object to make it a readonly object using "as const"
33+
const config = {
34+
api: {
35+
url: "https://api.example.com",
36+
version: "v1",
37+
},
38+
timeout: 5000,
39+
retries: 3,
40+
} as const;
41+
42+
// 7. Try to modify a property of the config object (this should cause a type error)
43+
// config.api.url = "https://new-api.example.com";
44+
45+
// ignore the line below
46+
export {};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Exercise 2.1: Inferred types
2+
// Identify and remove unnecessary type annotations
3+
4+
// Note: Typescript should not be complaining (no red squiggles) after
5+
// your changes
6+
7+
function add(a: number, b: number) {
8+
return a + b;
9+
}
10+
11+
function canBuy(itemPrice: number, balance: number) {
12+
const hasEnoughMoney = balance >= itemPrice;
13+
return hasEnoughMoney;
14+
}
15+
16+
function getFullName(firstName: string, lastName: string) {
17+
const fullName = `${firstName} ${lastName}`;
18+
return fullName;
19+
}
20+
21+
// ignore the line below
22+
export {};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Exercise 3.1: Overriding inferred types
2+
// Add explicit type annotations to fix the TypeScript errors
3+
4+
let a: number | null = 10; // Change this line
5+
a = null;
6+
7+
let b: null | string = "my string"; // Change this line
8+
b = null;
9+
10+
// ignore the line below
11+
export {};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Exercise 5.1: Object types and interfaces
2+
3+
// Create an interface/type Animal with properties name (string) and sound (string).
4+
type Animal = {
5+
name: string;
6+
sound: string;
7+
}
8+
9+
// Create an interface/type Dog that extends Animal and adds a property breed (string).
10+
type Dog = Animal & {
11+
breed: string;
12+
}
13+
14+
// Create a variable myDog of type Dog and assign it an object with appropriate values.
15+
const myDog: Dog = {
16+
name: 'dog',
17+
sound: 'bark',
18+
breed: 'chihuahua'
19+
}
20+
21+
// ignore the line below
22+
export {}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// EXERCISE 6.1: Optional properties and parameters
2+
// Add type annotations where necessary and modify the functions to handle optional parameters appropriately.
3+
4+
// 1. Refactor this function to use an optional parameter for 'title'
5+
function greet(name: string, title?: string) {
6+
if (title) {
7+
return `Hello, ${title} ${name}!`;
8+
}
9+
return `Hello, ${name}!`;
10+
}
11+
12+
// TESTS
13+
// Should work:
14+
console.log(greet("Alice", "Ms."));
15+
console.log(greet("Bob"));
16+
17+
// Should not work:
18+
// console.log(greet("Charlie", "Mr.", "Brown"));
19+
20+
21+
// 2. Define a type for User
22+
// - name
23+
// - age (optional)
24+
// - email (optional)
25+
// - isAdmin
26+
// - address (optional)
27+
type User = {
28+
name: string;
29+
age?: number | string;
30+
email?: string;
31+
isAdmin: boolean
32+
address?: Address;
33+
};
34+
35+
// 3. Define type for Address
36+
// - street
37+
// - city
38+
// - country
39+
type Address = {
40+
street: string;
41+
city: string;
42+
country: string;
43+
};
44+
45+
// 4. Create a type for the configuration object with optional properties
46+
type UserConfig = {
47+
name: string;
48+
age?: number;
49+
email?: string;
50+
isAdmin?: boolean;
51+
}; // Your implementation here
52+
53+
// 5. Refactor the function to take in UserConfig and return User.
54+
function createUser(config: UserConfig): User {
55+
return {
56+
name: config.name,
57+
age: config.age ?? "Unknown",
58+
email: config.email ?? "No email provided",
59+
isAdmin: config.isAdmin ?? false,
60+
};
61+
}
62+
63+
// TESTS
64+
// Should work:
65+
const user1 = createUser({
66+
name: "Charlie",
67+
age: 30,
68+
email: "charlie@example.com",
69+
});
70+
const user2 = createUser({ name: "David", isAdmin: true });
71+
72+
// 6. Add appriopriate type annotations
73+
// Then, refactor this function to use optional chaining and nullish coalescing
74+
function getFullAddress(user: User) {
75+
const street = user.address?.street
76+
?? "Unknown street";
77+
const city = user.address?.city ?? "Unknown city";
78+
const country = user.address?.country ?? "Unknown country";
79+
80+
return `${street}, ${city}, ${country}`;
81+
}
82+
83+
// 7. Create a type for the product with optional properties
84+
// - name
85+
// - price
86+
// - description (optional)
87+
// - category (optional)
88+
type Product = {
89+
name: string;
90+
price: number;
91+
description?: string;
92+
category?: string;
93+
}; // Your implementation here
94+
95+
// Then, refactor the function to use this type and handle optional properties
96+
function displayProductInfo(product: Product) {
97+
let info = `${product.name} - $${product.price}`;
98+
99+
if (product.description) {
100+
info += `\nDescription: ${product.description}`;
101+
}
102+
103+
if (product.category) {
104+
info += `\nCategory: ${product.category}`;
105+
}
106+
107+
return info;
108+
}
109+
110+
// TESTS
111+
// Should work:
112+
const product1 = {
113+
name: "Laptop",
114+
price: 999.99,
115+
description: "Powerful laptop for professionals",
116+
};
117+
const product2 = { name: "Mouse", price: 19.99 };
118+
console.log(displayProductInfo(product1));
119+
console.log(displayProductInfo(product2));
120+
121+
// ignore the line below
122+
export {}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// EXERCISE 7.1: Union and literal types
2+
// Use union types and literal types to improve the following code.
3+
// Add type annotations where necessary.
4+
5+
// 1. Create a union type for different shapes
6+
// Hint: Use "circle", "square", and "triangle" as literal types
7+
type Shape = "circle" | "square" | "triangle";
8+
9+
// 2. Create a type for a point in 2D space
10+
// The x and y coordinates should only allow -1, 0, or 1
11+
type Point = {
12+
x: -1 | 0 | 1;
13+
y: -1 | 0 | 1;
14+
};
15+
16+
// 3. Create a union type for different HTTP methods
17+
// Hint: Use "GET", "POST", "PUT", "DELETE" as literal types
18+
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
19+
20+
// 4. Create a type for API response status
21+
// It should allow "success" and "error" as string literals, or a number for the status code
22+
type ApiStatus = "success" | "error" | number;
23+
24+
// 5. Add type annotations to this function
25+
// It should accept the Shape type you defined and return a number
26+
function getArea(shape: Shape, size: number) {
27+
switch (shape) {
28+
case "circle":
29+
return Math.PI * size * size;
30+
case "square":
31+
return size * size;
32+
case "triangle":
33+
return (Math.sqrt(3) / 4) * size * size;
34+
}
35+
}
36+
37+
// 6. Add type annotations to this function
38+
// It should accept the Point type you defined and return a string
39+
function describePoint(point: Point) {
40+
return `(${point.x}, ${point.y})`;
41+
}
42+
43+
// 7. Add type annotations to this function
44+
// It should accept the HttpMethod type you defined and a URL string
45+
// The return type should be a union of 'string' and 'undefined'
46+
function makeRequest(method: HttpMethod, url: string): string | undefined {
47+
// Implementation not required
48+
return undefined;
49+
}
50+
51+
// 8. Create a type for a configuration object
52+
// It should have a mode property that only allows "development" or "production"
53+
// and an optional debug property that's a boolean
54+
type Config = {
55+
mode: "development" | "production";
56+
debug?: boolean;
57+
}
58+
59+
// 9. Add type annotations to this function
60+
// It should accept the Config type you defined
61+
function setConfig(config: Config) {
62+
// Implementation not required
63+
}
64+
65+
// 10. Create a literal type for valid status values
66+
type Status = "active" | "inactive" | "suspended";
67+
68+
// Then, refactor the function to use this type
69+
function updateStatus(status: Status) {
70+
if (status === "active" || status === "inactive" || status === "suspended") {
71+
// Update the status
72+
} else {
73+
throw new Error("Invalid status");
74+
}
75+
}
76+
77+
updateStatus("active");
78+
updateStatus("inactive");
79+
80+
// 11. Create a union type for possible log levels
81+
type LogLevel = "INFO" | "DEBUG" | "WARNING" | "ERROR";
82+
83+
// Then, refactor the function to use this type and add type annotations
84+
function log(message: string, level: LogLevel) {
85+
const timestamp = new Date().toISOString();
86+
console.log(`[${timestamp}] [${level}] ${message}`);
87+
}
88+
89+
log("Server started", "INFO");
90+
log("Database connection failed", "ERROR");
91+
92+
// Ignore this line
93+
export {};

0 commit comments

Comments
 (0)