mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-06-16 21:06:35 +08:00
feat(curriculum): add typescript review page (#59548)
Co-authored-by: Jessica Wilkins <67210629+jdwilkin4@users.noreply.github.com>
This commit is contained in:
parent
48c7901f91
commit
322e62ba90
@ -3570,7 +3570,8 @@
|
||||
"review-typescript": {
|
||||
"title": "Typescript Review",
|
||||
"intro": [
|
||||
"Review Typescript concepts to prepare for the upcoming quiz."
|
||||
"Before you take the TypeScript quiz, you should review everything you've learned so far.",
|
||||
"Open up this page to review all of the concepts taught including data types in TypeScript, generics, type narrowing and more."
|
||||
]
|
||||
},
|
||||
"quiz-typescript": {
|
||||
|
||||
@ -9,7 +9,251 @@ dashedName: review-typescript
|
||||
|
||||
Review the concepts below to prepare for the upcoming quiz.
|
||||
|
||||
## What is TypeScript
|
||||
|
||||
- **JavaScript**: JavaScript is a dynamically-typed language. This means that variables can receive any values at run time. The challenge of a dynamically-typed language is that the lack of type safety can introduce errors.
|
||||
|
||||
For example, even if your JavaScript function expects an array, you can still call it with a number:
|
||||
|
||||
```javascript
|
||||
const getRandomValue = (array) => {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
|
||||
console.log(getRandomValue(10));
|
||||
```
|
||||
|
||||
The `console` output for the example above will be `undefined`.
|
||||
|
||||
- **TypeScript**: TypeScript extends the JavaScript language to include static typing, which helps catch errors caused by type mismatches before you run your code.
|
||||
|
||||
For example, you can define a type for the `array` parameter as follows:
|
||||
|
||||
```typescript
|
||||
const getRandomValue = (array: string[]) => {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
```
|
||||
|
||||
This type definition tells TypeScript that the `array` parameter must be an array of strings. Then, when you call `getRandomValue` and pass it a number, you get an error called a compiler error.
|
||||
|
||||
- **Compiler**: You first need to compile TypeScript code into regular JavaScript. When you run the compiler, TypeScript will evaluate your code and throw an error for any issues where the types don't match.
|
||||
|
||||
## Data Types in TypeScript
|
||||
|
||||
- **Primitive Data Types in TypeScript**: For the primitive data types `string`, `null`, `undefined`, `number`, `boolean`, and `bigint`, TypeScript offers corresponding type keywords.
|
||||
|
||||
```typescript
|
||||
let str: string = "Naomi";
|
||||
let num: number = 42;
|
||||
let bool: boolean = true;
|
||||
let nope: null = null;
|
||||
let nada: undefined = undefined;
|
||||
```
|
||||
|
||||
- **Array**: You can define an array of specific type with two different syntaxes.
|
||||
|
||||
```typescript
|
||||
const arrOne: string[] = ["Naomi"];
|
||||
const arrTwo: Array<string> = ["Camperchan"];
|
||||
```
|
||||
|
||||
- **Objects**: You can define the exact structure of an object.
|
||||
|
||||
```typescript
|
||||
const obj: { a: string, b: number } = { a: "Naomi", b: 42 };
|
||||
```
|
||||
|
||||
If you want an object with any keys, but where all values must be strings, there are two ways to define it:
|
||||
|
||||
```typescript
|
||||
const objOne: Record<string, string> = {};
|
||||
const objTwo: { [key: string]: string } = {};
|
||||
```
|
||||
|
||||
- **Other Helpful Types in TypeScript**:
|
||||
- **`any`**: `any` indicates that a value can have any type. It tells the compiler to stop caring about the type of that variable.
|
||||
- **`unknown`**: `unknown` tells TypeScript that you _do_ care about the type of the value, but you don’t actually know what it is. `unknown` is generally preferred over `any`.
|
||||
- **`void`**: This is a special type that you’ll typically only use when defining functions. Functions that don’t have a return value use a return type of `void`.
|
||||
- **`never`**: It represents a type that will never exist.
|
||||
|
||||
- **`type` Keyword**: This keyword is like `const`, but instead of declaring a variable, you can declare a type.
|
||||
|
||||
It is useful for declaring custom types such as union types or types that include only specific values:
|
||||
|
||||
```typescript
|
||||
type stringOrNumber = string | number;
|
||||
type bot = "camperchan" | "camperbot" | "naomi";
|
||||
```
|
||||
|
||||
- **`interface`**: Interfaces are like classes for types. They can implement or extend other interfaces, are specifically object types, and are generally preferred unless you need a specific feature offered by a `type` declaration.
|
||||
|
||||
```typescript
|
||||
interface wowie {
|
||||
zowie: boolean;
|
||||
method: () => void;
|
||||
}
|
||||
```
|
||||
|
||||
- **Defining Return Type**: You can also define the _return type_ of the function.
|
||||
|
||||
The example below defines the return value as a string. If you try to return anything else, TypeScript will give a compiler error.
|
||||
|
||||
```typescript
|
||||
const getRandomValue = (array: string[]): string => {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
```
|
||||
|
||||
## Generics
|
||||
|
||||
- **Defining Generic Type**: You can define a generic type and refer to it in your function. It can be thought of as a special parameter you provide to a function to control the behavior of the function's type definition.
|
||||
|
||||
Here is an example of defining a generic type for a function:
|
||||
|
||||
```typescript
|
||||
const getRandomValue = <T>(array: T[]): T => {
|
||||
return array[Math.floor(Math.random() * array.length)];
|
||||
}
|
||||
const val = getRandomValue([1, 2, 4])
|
||||
```
|
||||
|
||||
The `<T>` syntax tells TypeScript that you are defining a generic type `T` for the function. `T` is a common name for generic types, but you can use any name.
|
||||
|
||||
Then, you tell TypeScript that the `array` parameter is an array of values matching the generic type, and that the returned value is a single element of that same type.
|
||||
|
||||
- **Specifying Type Argument in Function Call**: You can pass a type argument to a function call using angle brackets between the function name and its parameters.
|
||||
|
||||
Here is an example of passing a type argument to a function call:
|
||||
|
||||
```typescript
|
||||
const email = document.querySelector<HTMLInputElement>("#email");
|
||||
console.log(email.value);
|
||||
```
|
||||
|
||||
This tells TypeScript that the element you expect to find will be an input element.
|
||||
|
||||
## Type Narrowing
|
||||
|
||||
- **Narrowing by Truthiness**: In the example below, you get a compiler error trying to access the `value` property of `email` because `email` _might_ be `null`.
|
||||
|
||||
```typescript
|
||||
const email = document.querySelector<HTMLInputElement>("#email");
|
||||
console.log(email.value);
|
||||
```
|
||||
|
||||
You can use a conditional statement to confirm `email` is _truthy_ before accessing the property:
|
||||
|
||||
```typescript
|
||||
const email = document.querySelector<HTMLInputElement>("#email");
|
||||
if (email) {
|
||||
console.log(email.value);
|
||||
}
|
||||
```
|
||||
|
||||
Truthiness checks can also work in the reverse direction:
|
||||
|
||||
```typescript
|
||||
const email = document.querySelector<HTMLInputElement>("#email");
|
||||
if (!email) {
|
||||
throw new ReferenceError("Could not find email element!")
|
||||
}
|
||||
console.log(email.value);
|
||||
```
|
||||
|
||||
Throwing an error ends the logical execution of this code, which means when you reach the `console.log()` call, TypeScript knows `email` _cannot_ be `null`.
|
||||
|
||||
- **Optional Chaining**: Optional chaining `?.` is also a form of type narrowing, under the same premise that the property access can't happen if the `email` value is `null`.
|
||||
|
||||
```typescript
|
||||
const email = document.querySelector<HTMLInputElement>("#email");
|
||||
console.log(email?.value);
|
||||
```
|
||||
|
||||
- **`typeof` Operator**: You can use a conditional to check the type of the variable using the `typeof` operator.
|
||||
|
||||
```typescript
|
||||
const myVal = Math.random() > 0.5 ? 222 : "222";
|
||||
if (typeof myVal === "number") {
|
||||
console.log(myVal / 10);
|
||||
}
|
||||
```
|
||||
|
||||
- **`instanceof` Keyword**: If the object comes from a class, you can use the `instanceof` keyword to narrow the type.
|
||||
|
||||
```typescript
|
||||
const email = document.querySelector("#email");
|
||||
|
||||
if (email instanceof HTMLInputElement) {
|
||||
console.log(email.value);
|
||||
}
|
||||
```
|
||||
|
||||
- **Casting**: When TypeScript cannot automatically determine the type of a value, such as the result from `request.json()` method in the example below, you'll get a compiler error. One way to resolve this is by casting the type, but doing so weakens TypeScript's ability to catch potential errors.
|
||||
|
||||
```typescript
|
||||
interface User {
|
||||
name: string;
|
||||
age: number;
|
||||
}
|
||||
|
||||
const printAge = (user: User) =>
|
||||
console.log(`${user.name} is ${user.age} years old!`)
|
||||
|
||||
const request = await fetch("url")
|
||||
const myUser = await request.json() as User;
|
||||
printAge(myUser);
|
||||
```
|
||||
|
||||
- **Type Guard**: Instead of casting the type, you can write a type guard:
|
||||
|
||||
```typescript
|
||||
interface User {
|
||||
name: string;
|
||||
age: number;
|
||||
}
|
||||
|
||||
const isValidUser = (user: unknown): user is User => {
|
||||
return !!user &&
|
||||
typeof user === "object" &&
|
||||
"name" in user &&
|
||||
"age" in user;
|
||||
}
|
||||
```
|
||||
|
||||
The `user is User` syntax indicates that your function returns a boolean value, which when true means the `user` value satisfies the `User` interface.
|
||||
|
||||
## `tsconfig` File
|
||||
|
||||
- **`tsconfig.json`**: TypeScript's compiler settings live in a `tsconfig.json` file in the root directory of your project.
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./prod",
|
||||
"lib": ["ES2023"],
|
||||
"target": "ES2023",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "Node",
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true
|
||||
},
|
||||
"exclude": ["test/"]
|
||||
}
|
||||
```
|
||||
|
||||
Here are descriptions of the compiler options used in the example above:
|
||||
|
||||
- **`compilerOptions`**: The `compilerOptions` property is where you control how the TypeScript compiler behaves.
|
||||
- **`rootDir` and `outDir`**: The `rootDir` and `outDir` tell TypeScript which directory holds your source files, and which directory should contain the transpiled JavaScript code.
|
||||
- **`lib`**: The `lib` property determines which type definitions the compiler uses, and allows you to include support for specific ES releases, the DOM, and more.
|
||||
- **`module` and `moduleResolution`**: The `module` and `moduleResolution` work in tandem to manage how your package uses modules - either CommonJS or ECMAScript.
|
||||
- **`esModuleInterop`**: The `esModuleInterop` allows for smoother interoperability between CommonJS and ES modules by automatically creating namespace objects for imports.
|
||||
- **`skipLibCheck`**: The `skipLibCheck` option skips validating `.d.ts` files that aren't referenced by imports in your code.
|
||||
- **`strict`**: The `strict` flag enables several checks, such as ensuring proper handling of nullable types and warning when TypeScript falls back to `any`.
|
||||
- **`exclude`**: The top-level `exclude` property tells the compiler to ignore these TypeScript files during compilation.
|
||||
|
||||
# --assignment--
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user