diff --git a/.languagetool.cfg b/.languagetool.cfg
new file mode 100644
index 0000000..4170c47
--- /dev/null
+++ b/.languagetool.cfg
@@ -0,0 +1 @@
+disabledRules=EN_COMPOUNDS_PRE_CLASS,ENGLISH_WORD_REPEAT_RULE,EN_UNPAIRED_QUOTES,LC_AFTER_PERIOD[1],ID_CASING[2]
diff --git a/README.md b/README.md
index 7d4035d..49a749a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# exercises-typescript
-[](../../actions)
+[](../../actions)
## How to contribute
diff --git a/description.en.yml b/description.en.yml
new file mode 100644
index 0000000..55b0bb0
--- /dev/null
+++ b/description.en.yml
@@ -0,0 +1,24 @@
+---
+title: |
+ TypeScript course: free training for developers
+header: Typescript
+description: |
+ In modern development, TypeScript has not just taken a firm place, but has replaced JavaScript in many places. Knowledge of TypeScript has become essential for any developer who works with either Node.js or the browser
+seo_description: |
+ Sharpen your knowledge in a free Typescript course | Interactive exercises right in your browser | Free TypeScript course from CodeBasics
+
+keywords:
+ - typescript
+ - typoscript
+ - type script
+ - тайпскрипт
+ - ts
+ - тс
+ - тайп скрипт
+ - онлайн курс
+ - бесплатный курс
+ - программирование
+ - code basics
+ - online course
+ - free course
+ - programming
diff --git a/modules/10-basics/10-hello-world/en/EXERCISE.md b/modules/10-basics/10-hello-world/en/EXERCISE.md
new file mode 100644
index 0000000..7f338c0
--- /dev/null
+++ b/modules/10-basics/10-hello-world/en/EXERCISE.md
@@ -0,0 +1,5 @@
+Copy the exact code from the instructions into the editor and execute it by clicking “Run”.
+
+```typescript
+console.log('Hello, World!');
+```
diff --git a/modules/10-basics/10-hello-world/en/README.md b/modules/10-basics/10-hello-world/en/README.md
new file mode 100644
index 0000000..ec388fc
--- /dev/null
+++ b/modules/10-basics/10-hello-world/en/README.md
@@ -0,0 +1,16 @@
+
+As is tradition, we'll start by writing a 'Hello, World!' program. The program will print the following text:
+
+
+ Hello, World!
+
+
+To print something, you need to give computer a special command. In TypeScript, we use console.log().
+
+## Launch special features
+
+The TypeScript compiler works slower than needed for code-basics exercises. Because of this, TypeScript errors in this course are only shown in the editor itself - highlighted in red and revealed when you hover.
+
+During the exercise execution, only JavaScript errors are shown. This means that you should make sure that there are no red underscores in the editor before checking the code.
+
+If you want to test the examples on your computer for correct behavior, make sure you use the `--strict` flag.
diff --git a/modules/10-basics/10-hello-world/en/data.yml b/modules/10-basics/10-hello-world/en/data.yml
new file mode 100644
index 0000000..2364625
--- /dev/null
+++ b/modules/10-basics/10-hello-world/en/data.yml
@@ -0,0 +1,9 @@
+---
+name: Hello, World!
+tips:
+ - |
+ [Repl for experimenting with TypeScript](https://www.typescriptlang.org/play)
+ - |
+ [strict in tsconfig](https://www.typescriptlang.org/tsconfig#strict)
+ - >
+ [TypeScript compiler options](https://www.typescriptlang.org/docs/handbook/compiler-options.html#compiler-options)
diff --git a/modules/10-basics/20-typescript-as-a-second-language/en/EXERCISE.md b/modules/10-basics/20-typescript-as-a-second-language/en/EXERCISE.md
new file mode 100644
index 0000000..485dc13
--- /dev/null
+++ b/modules/10-basics/20-typescript-as-a-second-language/en/EXERCISE.md
@@ -0,0 +1,7 @@
+
+Using the sum example from the lesson, write a function that finds the product of the given numbers:
+
+```typescript
+multiply(3, 8); // 24
+multiply(1, 2); // 2
+```
diff --git a/modules/10-basics/20-typescript-as-a-second-language/en/README.md b/modules/10-basics/20-typescript-as-a-second-language/en/README.md
new file mode 100644
index 0000000..5678cc4
--- /dev/null
+++ b/modules/10-basics/20-typescript-as-a-second-language/en/README.md
@@ -0,0 +1,124 @@
+
+TypeScript is given as a second language in our project. Therefore, you should know JavaScript to better understand the course material.
+
+You should also have an understanding of data types, variables, conditional constructs, loops, functions, object properties and methods, and anonymous or lambda functions.
+
+Learning a second programming language is easier than learning a first one, so the structure of the material changes a lot. Here we review the basic constructs to quickly familiarize ourselves with the syntax. Then we move on to the tasks for which TypeScript is studied.
+
+In this tutorial, we'll learn what TypeScript is, as well as break down its features, installation, and getting it up and running.
+
+## What is TypeScript
+
+TypeScript is JavaScript with an additional syntax for specifying data types. The first one refers to statically typed languages, the second one to dynamically typed languages.
+
+To learn more about TypeScript, let's compare it to JavaScript.
+
+Dynamically typed languages like JavaScript have an interpreter, a program that executes code line by line without prior analysis:
+
+```bash
+# node (Node.js) — JavaScript interpreter
+# The code is immediately launched for execution
+node index.js
+```
+
+If there are type errors in such a code, for example, a number of `BigInt` type came into the function instead of a regular number, we will learn about the error only when we run the code:
+
+```javascript
+function sum(a, b) {
+ return a + b;
+}
+
+sum(10n, 5); // oops
+// 10n is a number of BigInt type, adding it to a regular number will cause a runtime error
+// Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
+```
+
+Statically typed languages like TypeScript work differently. They have a number of advantages:
+
+* Finding some types of errors even before the code is executed
+* Easier code refactoring
+* Full support for editor features: autocomplete add-ons, code navigation, etc.
+
+Before you can run code in TypeScript for execution, you must compile it.
+
+During compilation, it is checked that the program is **type-safe** - it does not contain errors like the example above. If the compiler finds a type mismatch, it stops compilation and displays warnings about where the types do not match.
+
+Same example in TypeScript:
+
+```typescript
+function sum(a: number, b: number) {
+ return a + b;
+}
+
+sum(10n, 5);
+// An error will occur at the compile stage
+// Argument of type 'bigint' is not assignable to parameter of type 'number'.
+```
+
+Not only will the code above fail to run, but it will also fail to compile. The TypeScript compiler will stop execution and indicate a type mismatch error.
+
+If we look at the function definition, we can see that we are facing almost the same JavaScript, except for the type description of input variables in the function.
+It says that parameters `a` and `b` have type `number`. The rest of the TypeScript code is annotated with types in much the same way. The type descriptions can be very complex in places, but the idea remains the same.
+
+We cannot say unequivocally which approach is better - static or dynamic typing. It all depends on the specific situation, and successful projects can be written in different languages. Since we are studying TypeScript in this
+course, we will look at the peculiarities of working with it.
+
+## TypeScript Features
+
+TypeScript has become one of the most popular typed languages due to the following features:
+
+* TypeScript is almost completely compatible with JavaScript in terms of features and types. Everything written in
+ TypeScript is also available in JavaScript, and vice versa. TypeScript is called a superset of the JavaScript
+ language. Meaning that it is the same JavaScript + type description.
+* The TypeScript compiler turns TypeScript code into JavaScript code. That is, it removes type definitions from TypeScript code. This process is also known as **transpilation**.
+* The developer of TypeScript is Microsoft
+* Strong typing
+
+Let's look at the last feature in more detail.
+
+### Strong typing
+
+Strong typing is not related to static typing. It refers to the extent to which a language allows automatic type conversions. A static language can be weak, and vice versa.
+
+For example, in JavaScript we can add a number to a string. When the language encounters such a construct, it will automatically perform a type conversion: `10 + 'one'`.
+TypeScript won't do that. It will generate an error: `The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type`.
+
+Many dynamic languages are strongly typed. For example, Ruby and Python are among them. Strong typing only makes the language better and does not complicate the process of programming.
+
+We've covered the advantages and features of TypeScript. Now you can learn how to install it.
+
+## How to install and run TypeScript
+
+TypeScript is written in TypeScript, which is then transpiled into JavaScript and distributed as a normal npm package. The installation of TypeScript is therefore very simple:
+
+```bash
+# Node.js have to be installed
+# Inside the project, where TypeScript will be used
+npm install typescript
+```
+
+Then you need to create TypeScript source files. These have the extension *ts*. The TypeScript compiler is available through the `tsc` utility:
+
+```bash
+npx tsc index.ts
+```
+
+The output is a file with JavaScript code that can already be executed with Node.js:
+
+```bash
+node index.js
+```
+
+You can also supply the package [ts-node](https://github.com/TypeStrong/ts-node), which compiles and runs at the same time. This package provides a REPL for experimenting with TypeScript.
+
+## Conclusions
+
+In this lesson, we learned about the TypeScript language. We learned that it is the same as JavaScript, but with additional syntax for specifying data types. TypeScript has several advantages over JavaScript:
+
+* Finding some errors even before the code is executed
+* Easier code refactoring
+* Full support for editor features: autocomplete add-ons, code navigation, etc.
+
+It is impossible to say which language is better. It all depends on the specific task and features of the language.
+
+We also learned about the features of TypeScript in this lesson, and we also learned how to install and run it.
\ No newline at end of file
diff --git a/modules/10-basics/20-typescript-as-a-second-language/en/data.yml b/modules/10-basics/20-typescript-as-a-second-language/en/data.yml
new file mode 100644
index 0000000..cbf68dc
--- /dev/null
+++ b/modules/10-basics/20-typescript-as-a-second-language/en/data.yml
@@ -0,0 +1,10 @@
+---
+name: TypeScript
+tips:
+ - |
+ [Telegram Hexlet: JavaScript/TypeScript](https://t.me/hexletcommunity/12)
+ - >
+ [TypeScript boilerplate](https://github.com/hexlet-boilerplates/typescript-package)
+ - >
+ [Playground with the ability
+ to see the result of TypeScript to JavaScript transpilation](https://www.typescriptlang.org/play)
diff --git a/modules/10-basics/30-variables/en/EXERCISE.md b/modules/10-basics/30-variables/en/EXERCISE.md
new file mode 100644
index 0000000..d55cc3c
--- /dev/null
+++ b/modules/10-basics/30-variables/en/EXERCISE.md
@@ -0,0 +1,7 @@
+
+Complete the body of the `repeat()` function that repeats the string the specified number of times. The function should return the result. Try not to use built-in methods, you will need a loop for this implementation.
+
+```typescript
+repeat('hexlet', 2); // hexlethexlet
+repeat('wo', 3); // wowowo
+```
diff --git a/modules/10-basics/30-variables/en/README.md b/modules/10-basics/30-variables/en/README.md
new file mode 100644
index 0000000..9fc945f
--- /dev/null
+++ b/modules/10-basics/30-variables/en/README.md
@@ -0,0 +1,92 @@
+
+In this lesson we will learn how TypeScript and JavaScript differ in terms of working with variables. We will learn what type inference is and why it is necessary in programming. We'll also learn why TypeScript doesn't require you to manually specify the type of variables.
+
+## Type inference
+
+Variables and constants in TypeScript are defined in the same way as in JavaScript:
+
+```typescript
+let age = 10;
+
+let company = 'Hexlet';
+let user = {
+ firstName: 'Miro',
+};
+let fruits = ['apple', 'banana'];
+```
+
+In doing so, TypeScript does some extra work in the background. It automatically associates a variable or constant with the data type of the initial value. In programming, this process is called **type inference**.
+
+The type of the variable cannot change:
+
+```typescript
+let age = 10;
+// OK since it's the same type (Number)
+age = 11.1;
+
+// Type 'string' is not assignable to type 'number'.
+age = 'some string'; // Error!
+```
+
+If we try to pass this variable to a method that expects a different type, that too will result in an error:
+
+```typescript
+// Argument of type 'number' is not assignable to parameter
+// of type '(substring: string, ...args: any[])
+'hexlet'.replace('xl', age);
+```
+
+Static typing imposes a restriction on arrays. Only data of one type can be stored inside:
+
+```typescript
+let items = [1, 2, 3];
+items.push(4); // OK
+
+// Argument of type 'string' is not assignable to parameter of type 'number'.
+items.push('code-basics'); // Error!
+```
+
+With objects, the situation is even stricter. In TypeScript, you cannot not only change the type of properties inside an object, but also add new properties dynamically:
+
+```typescript
+let user = {
+ firstName: 'Miro',
+};
+
+// Property 'lastName' does not exist on type '{ firstName: string; }'.
+user.lastName = 'Smith';
+```
+
+## Explicit type indication
+
+TypeScript allows you to explicitly specify the type of variables. In practice, however, you rarely need to do this manually, since type inference works automatically:
+
+```typescript
+let name: string = 'Alice';
+const count: number = 100;
+let canPlay: boolean = true;
+```
+
+## Null
+
+By default, in TypeScript variables can only contain the specified type with no exceptions, for example, we cannot assign null:
+
+```typescript
+let age = 30;
+age = null; // Error!
+```
+
+This behavior protects us from many errors that are related to the fact that there are no checks for null. At the same time, `null` is sometimes an acceptable value. In this case, a special Union Type is used:
+
+```typescript
+let age: number | null = 30;
+age = null;
+```
+
+Here we have specified that the type of the `age` variable is `number | null`. It is read as “number or null”.
+
+Union Type is an interesting and handy concept that we'll look at in more detail later.
+
+## Conclusions
+
+In this lesson, we learned about variables in TypeScript. We learned how TypeScript differs from JavaScript in terms of working with variables. We also learned why you don't have to manually specify the type of variables in TypeScript.
\ No newline at end of file
diff --git a/modules/10-basics/30-variables/en/data.yml b/modules/10-basics/30-variables/en/data.yml
new file mode 100644
index 0000000..d679009
--- /dev/null
+++ b/modules/10-basics/30-variables/en/data.yml
@@ -0,0 +1,9 @@
+---
+name: Variables
+tips:
+ - >
+ [Method
+ String.repeat()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/repeat)
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/2/basic-types.html)
diff --git a/modules/10-basics/40-named-functions/en/EXERCISE.md b/modules/10-basics/40-named-functions/en/EXERCISE.md
new file mode 100644
index 0000000..13bca0e
--- /dev/null
+++ b/modules/10-basics/40-named-functions/en/EXERCISE.md
@@ -0,0 +1,12 @@
+
+Implement the `getHiddenCard()` function. It takes as input a credit card number, which consists of 16 digits, as a string and returns a hidden version of it. This version can be used on the site for display. For example, if the original card number was *2034399002125581*, the hidden version looks like this: *\*\*\*\*5581*.
+
+The function replaces the first 12 characters with asterisks. The number of asterisks is controlled by the second optional parameter. The default value is 4.
+
+```typescript
+// The credit card is passed as a string
+getHiddenCard('1234567812345678', 2) // "**5678"
+getHiddenCard('1234567812345678', 3) // "***5678"
+getHiddenCard('1234567812345678') // "****5678"
+getHiddenCard('2034399002121100', 1) // "*1100"
+```
diff --git a/modules/10-basics/40-named-functions/en/README.md b/modules/10-basics/40-named-functions/en/README.md
new file mode 100644
index 0000000..1672040
--- /dev/null
+++ b/modules/10-basics/40-named-functions/en/README.md
@@ -0,0 +1,74 @@
+
+In the definition of a variable, we usually do not specify its type, as it is derived automatically. This does not work with functions. You must specify the types of all input parameters for them.
+
+In this tutorial we will learn how to make a parameter optional, whether something should be done with the default value of a variable, and how to output the type of the return value.
+
+## Mandatory parameter
+
+Let's define the function and specify the type of input parameter:
+
+```typescript
+function getGreetingPhrase(name: string) {
+ return `Hello, ${name.toUpperCase()}!`;
+}
+```
+
+When specified like this, the parameter will be mandatory. If you call a function without a parameter, it will cause a compilation error:
+
+```typescript
+// Expected 1 arguments, but got 0.
+getGreetingPhrase();
+```
+
+## Optional parameter
+
+To make a parameter optional, you must add a “?” after the variable name:
+
+```typescript
+function getGreetingPhrase(name?: string) {
+ return `Hello, ${name ? name.toUpperCase() : 'Guest'}!`;
+}
+
+getGreetingPhrase('Mike'); // Hello, MIKE!
+getGreetingPhrase(); // Hello, Guest!
+```
+
+In this case, the type of the `name` variable becomes composite (Union Type): `string | undefined` - string or undefined.
+
+An optional parameter can be `undefined` but not `null`. To add `null`, you need to change the definition like this:
+
+```typescript
+function getGreetingPhrase(name?: string | null) {
+ return `Hello, ${name ? name.toUpperCase() : 'Guest'}!`;
+}
+```
+
+Here we have extended the type definition of the variable `name` to `string | undefined | null`.
+
+## Default value
+
+With the default value, you do not need to specify anything additional. The value is set as in JavaScript. The variable itself automatically becomes optional, and the type is inferred based on the passed value:
+
+```typescript
+function getGreetingPhrase(name = 'Guest') {
+ return `Hello, ${name.toUpperCase()}!`;
+}
+
+getGreetingPhrase() // Hello, GUEST!
+```
+
+## Return value type
+
+In many cases, TypeScript outputs the type of the return value by itself, but it can be specified explicitly:
+
+```typescript
+function getGreetingPhrase(name: string): string {
+ return `Hello, ${name.toUpperCase()}!`;
+}
+```
+
+The returned type can be inferred, but sometimes the [resulting type](https://stackoverflow.com/questions/70001511/why-specify-function-return-types) is not what we expect. For this reason, we always recommend writing the type explicitly. This simplifies documentation and protects the code from accidental changes.
+
+## Conclusions
+
+In this lesson, we learned how to make a parameter optional, how to work with the default value of a variable, and how to output the type of the return value.
\ No newline at end of file
diff --git a/modules/10-basics/40-named-functions/en/data.yml b/modules/10-basics/40-named-functions/en/data.yml
new file mode 100644
index 0000000..dc58b0d
--- /dev/null
+++ b/modules/10-basics/40-named-functions/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Named functions
diff --git a/modules/10-basics/45-anonymous-functions/en/EXERCISE.md b/modules/10-basics/45-anonymous-functions/en/EXERCISE.md
new file mode 100644
index 0000000..ed4b635
--- /dev/null
+++ b/modules/10-basics/45-anonymous-functions/en/EXERCISE.md
@@ -0,0 +1,2 @@
+
+Write a function that returns an array of even numbers from the array `numbers`.
diff --git a/modules/10-basics/45-anonymous-functions/en/README.md b/modules/10-basics/45-anonymous-functions/en/README.md
new file mode 100644
index 0000000..1fac2ef
--- /dev/null
+++ b/modules/10-basics/45-anonymous-functions/en/README.md
@@ -0,0 +1,23 @@
+
+In this lesson, we will learn about anonymous functions. Together with arrow functions, they are usually used in the same place where they are defined. Because of this, TypeScript can output the types of their parameters.
+
+To define anonymous functions, the type indication is omitted:
+
+```typescript
+const fruits = ['banana', 'mango', 'apple'];
+const upperFruits = fruits.map((name) => name.toUpperCase());
+// ['BANANA', 'MANGO', 'APPLE']
+```
+
+This process is called **contextual typing** because the context of the function definition allows you to deduce the types of input parameters. As a result, the code looks identical to JavaScript code.
+
+If a function is defined out of context, the same rules apply as to named functions. Parameter types must be specified at the time of definition:
+
+```typescript
+const toUpper = (name: string): string => name.toUpperCase();
+const upperFruits = fruits.map(toUpper);
+```
+
+## Conclusions
+
+In this lesson, we looked at how to define anonymous functions and use them in different contexts. Anonymous functions can make code more readable and understandable.
\ No newline at end of file
diff --git a/modules/10-basics/45-anonymous-functions/en/data.yml b/modules/10-basics/45-anonymous-functions/en/data.yml
new file mode 100644
index 0000000..e06df18
--- /dev/null
+++ b/modules/10-basics/45-anonymous-functions/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Anonymous functions
diff --git a/modules/10-basics/50-arrays/en/EXERCISE.md b/modules/10-basics/50-arrays/en/EXERCISE.md
new file mode 100644
index 0000000..af0b237
--- /dev/null
+++ b/modules/10-basics/50-arrays/en/EXERCISE.md
@@ -0,0 +1,19 @@
+
+Anagrams are words that are made up of the same letters. For example:
+
+ dusty — study
+ elbow — below
+ peach — cheap
+
+Implement the `filterAnagrams()` function that finds all anagrams of a word. The function accepts a source word and a list to check - an array. And the function returns an array of all anagrams. If there is no anagram in the list, an empty array is returned:
+
+```typescript
+filterAnagrams('abba', ['aabb', 'abcd', 'bbaa', 'dada']);
+// ['aabb', 'bbaa']
+
+filterAnagrams('racer', ['crazer', 'carer', 'racar', 'caers', 'racer']);
+// ['carer', 'racer']
+
+filterAnagrams('laser', ['lazing', 'lazy', 'lacer']);
+// []
+```
diff --git a/modules/10-basics/50-arrays/en/README.md b/modules/10-basics/50-arrays/en/README.md
new file mode 100644
index 0000000..5dab279
--- /dev/null
+++ b/modules/10-basics/50-arrays/en/README.md
@@ -0,0 +1,32 @@
+
+In this lesson, we'll talk about arrays. TypeScript knows how to output their type, just as it does with primitive data types:
+
+```typescript
+const fruits = ['banana', 'mango', 'apple'];
+// Everything works
+const upperFruits = fruits.map((name) => name.toUpperCase());
+
+// Here, it does not
+// Property 'key' does not exist on type 'string'.
+const upperFruits = fruits.map((name) => name.key);
+```
+
+**Array** is a composite data type that is a container for another type. For example, the type “array of numbers” or “array of strings” are containers that contain strings or numbers.
+
+To denote such a type, square brackets are used: `number[]`, `string[]`.
+
+The definition of an array above could be written as follows:
+
+```typescript
+const fruits: string[] = ['banana', 'mango', 'apple'];
+```
+
+This is also how types are described in function definitions:
+
+```typescript
+function toUpperArray(items: string[]): string[] {
+ return items.map((s) => s.toUpperCase());
+}
+```
+
+In conclusion, arrays can be useful tools when working with data.
\ No newline at end of file
diff --git a/modules/10-basics/50-arrays/en/data.yml b/modules/10-basics/50-arrays/en/data.yml
new file mode 100644
index 0000000..79afcd4
--- /dev/null
+++ b/modules/10-basics/50-arrays/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Arrays
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#arrays)
diff --git a/modules/10-basics/55-objects/en/EXERCISE.md b/modules/10-basics/55-objects/en/EXERCISE.md
new file mode 100644
index 0000000..4c23b2b
--- /dev/null
+++ b/modules/10-basics/55-objects/en/EXERCISE.md
@@ -0,0 +1,11 @@
+
+Implement the `isComplete()` function that takes a course as input and determines if it is complete. A course is considered complete if four or more lessons have been added to it:
+
+```typescript
+// Determine the type based on the structure of the object
+const course = {
+ name: 'Java',
+ lessons: ['variables', 'functions', 'conditions'],
+};
+isComplete(course); // false
+```
diff --git a/modules/10-basics/55-objects/en/README.md b/modules/10-basics/55-objects/en/README.md
new file mode 100644
index 0000000..ce7212e
--- /dev/null
+++ b/modules/10-basics/55-objects/en/README.md
@@ -0,0 +1,56 @@
+
+In this lesson, let's learn about the types of an object. They consist of the types of all the properties included in it.
+
+The types are inferred automatically:
+
+```typescript
+// Тип: { firstName: string, pointsCount: number }
+const user = {
+ firstName: 'Mike',
+ pointsCount: 1000,
+};
+
+// Property types are unchangeable
+// Type 'number' is not assignable to type 'string'.
+user.firstName = 7;
+```
+
+TypeScript does not allow you to refer to properties that do not exist. This means that the structure of any object must be specified when it is initialized:
+
+```typescript
+// Property 'age' does not exist on type '{ firstName: string, pointsCount: number; }'.
+user.age = 100;
+```
+
+To accept such an object into a function as a parameter, you must specify its structure in the function description:
+
+```typescript
+// Properties in the type description are separated by commas (,)
+function doSomething(user: { firstName: string, pointsCount: number }) {
+ // ...
+}
+```
+
+Now any object that matches properties can be passed to the function:
+
+```typescript
+doSomething({ firstName: 'Alice', pointsCount: 2000 });
+doSomething({ firstName: 'Bob', pointsCount: 1800 });
+
+// Is not allowed
+doSomething({ firstName: 'Bob' });
+// Not allowed as well
+doSomething({ firstName: 'Bob', pointsCount: 1800, key: 'another' });
+```
+
+As with primitive data types, neither null nor undefined is allowed by default. To change this behavior, you need to add an optionality:
+
+```typescript
+// firstName can be undefined
+// pointsCount can be null
+function doSomething(user: { firstName?: string, pointsCount: number | null }) {
+ // ...
+}
+```
+
+Objects can be useful tools in software development.
\ No newline at end of file
diff --git a/modules/10-basics/55-objects/en/data.yml b/modules/10-basics/55-objects/en/data.yml
new file mode 100644
index 0000000..77f5dde
--- /dev/null
+++ b/modules/10-basics/55-objects/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Object Types
diff --git a/modules/10-basics/60-enums/en/EXERCISE.md b/modules/10-basics/60-enums/en/EXERCISE.md
new file mode 100644
index 0000000..dec1140
--- /dev/null
+++ b/modules/10-basics/60-enums/en/EXERCISE.md
@@ -0,0 +1,13 @@
+
+1. Implement a `ModalStatus` enumeration with two values: Opened and Closed
+2. Implement the `buildModal()` function. It returns an object that describes a modal window. Function parameters:
+
+ * The text that should be inside the window after initialization
+ * Status with which to create a window object
+
+The function returns an object with two fields: `text` (here the transmitted text is stored) and `status` (here the transmitted status is stored)
+
+```typescript
+const modal = buildModal('hexlet forever', ModalStatus.Opened);
+// { text: 'hexlet forever', status: ModalStatus.Opened }
+```
diff --git a/modules/10-basics/60-enums/en/README.md b/modules/10-basics/60-enums/en/README.md
new file mode 100644
index 0000000..0ef3095
--- /dev/null
+++ b/modules/10-basics/60-enums/en/README.md
@@ -0,0 +1,100 @@
+
+## Using enums
+
+In this lesson, we will learn about enumerations (commonly known as enums). This language construct allows you to create a set of names and then refer to them.
+
+Enums are used in place of strings for constant values:
+
+```typescript
+enum OrderStatus {
+ Created,
+ Paid,
+ Shipped,
+ Delivered,
+}
+
+const order = {
+ items: 3,
+ status: OrderStatus.Created,
+};
+```
+
+The most common use case for enums is storing different statuses. But there are other cases as well. For example, they are used to storing various reference data and get rid of magic values:
+
+* Movement directions
+* Sides of the world
+* Days of the week
+* Months
+
+```typescript
+enum CardinalDirection {
+ North,
+ South,
+ East,
+ West,
+}
+
+const direction = CardinalDirection.North;
+```
+
+An enum is both a value and a type. It can be specified as a type in function parameters:
+
+```typescript
+setStatus(status: OrderStatus)
+```
+
+Also, enums are turned into a JavaScript object after compilation, where each value corresponds to a property. This property has type `number` and starts with `0`:
+
+```typescript
+const status = OrderStatus.Created;
+console.log(status); // 0
+```
+
+This allows for convenient use of standard methods - for example, `Object.keys` and `Object.values` - in the future:
+
+```typescript
+const statuses = Object.keys(OrderStatus);
+console.log(statuses); // ['0', '1', '2', '3', 'Created', 'Paid', 'Shipped', 'Delivered']
+```
+
+Among the keys we see the numbers `'0', '1', '2', '3'`. The compiler creates such numeric keys automatically, and the created object looks like this:
+
+```typescript
+console.log(OrderStatus); // =>
+// {
+// '0': 'Created',
+// '1': 'Paid',
+// '2': 'Shipped',
+// '3': 'Delivered',
+// 'Created': 0,
+// 'Paid': 1,
+// 'Shipped': 2,
+// 'Delivered': 3
+// }
+```
+
+But we can get rid of creating additional keys by specifying string values:
+
+```typescript
+enum OrderStatus {
+ Created = '0',
+ Paid = '1',
+ Shipped = '2',
+ Delivered = '3',
+}
+
+const statuses = Object.keys(OrderStatus);
+console.log(statuses); // ['Created', 'Paid', 'Shipped', 'Delivered']
+
+console.log(OrderStatus); // =>
+// {
+// 'Created': '0',
+// 'Paid': '1',
+// 'Shipped': '2',
+// 'Delivered': '3'
+// }
+```
+
+## Conclusions
+
+In this lesson, we learned what an enumeration is used for and how it is used. We also learned that it can be specified as a type in function parameters.
\ No newline at end of file
diff --git a/modules/10-basics/60-enums/en/data.yml b/modules/10-basics/60-enums/en/data.yml
new file mode 100644
index 0000000..dac07ed
--- /dev/null
+++ b/modules/10-basics/60-enums/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Enums
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/enums.html)
diff --git a/modules/10-basics/60-enums/ru/EXERCISE.md b/modules/10-basics/60-enums/ru/EXERCISE.md
index e70cd8d..7b5f88a 100644
--- a/modules/10-basics/60-enums/ru/EXERCISE.md
+++ b/modules/10-basics/60-enums/ru/EXERCISE.md
@@ -2,8 +2,8 @@
1. Реализуйте перечисление `ModalStatus` с двумя значениями: Opened и Closed
2. Реализуйте функцию `buildModal()`. Он возвращает объект, который описывает модальное окно. Параметры функции:
- * Текст, который должен быть внутри окна после инициализации
- * Статус, с которым надо создать объект окна
+ * Текст, который должен быть внутри окна после инициализации;
+ * Статус, с которым надо создать объект окна.
Функция возвращает объект с двумя полями: `text` (здесь хранится переданный текст) и `status` (здесь хранится переданный статус)
diff --git a/modules/10-basics/70-type-aliases/en/EXERCISE.md b/modules/10-basics/70-type-aliases/en/EXERCISE.md
new file mode 100644
index 0000000..69ebc8c
--- /dev/null
+++ b/modules/10-basics/70-type-aliases/en/EXERCISE.md
@@ -0,0 +1,8 @@
+
+Implement the `getOlderUser()` function that takes two users as input and returns the one who is older. If the users are of the same age, `null` is returned:
+
+```typescript
+const user1 = { name: 'Petr', age: 8 };
+```
+
+Define an alias for the user to avoid duplicating the definition of its type in the function parameters.
\ No newline at end of file
diff --git a/modules/10-basics/70-type-aliases/en/README.md b/modules/10-basics/70-type-aliases/en/README.md
new file mode 100644
index 0000000..96d76dc
--- /dev/null
+++ b/modules/10-basics/70-type-aliases/en/README.md
@@ -0,0 +1,91 @@
+
+Let's imagine a program that has a user object. This object is used everywhere. In such a situation, the description of the type of this object will be repeated in each function definition:
+
+```typescript
+function doSomething(user: { firstName: string, lastName: number }) {}
+function doSomethingElse(user: { firstName: string, lastName: number }) {}
+function doSomethingAnother(user: { firstName: string, lastName: number }) {}
+````
+
+First, there is a lot of duplication. Secondly, it is much more difficult to change the structure, because you will have to edit all the places where this definition appears. In this lesson, let's learn how to avoid such problems.
+
+## Specify an alias of type
+
+To avoid doing the same work, TypeScript allows you to specify an alias for compound types. This way we don't have to repeat ourselves:
+
+```javascript
+type User = {
+ firstName: string;
+ pointsCount: number;
+}
+```
+
+It is now possible to change this in all functions:
+
+```typescript
+function doSomething(user: User) {
+ // ...
+}
+```
+
+An alias is not the creation of a new data type. It is a way to abbreviate the type definition. Therefore, the following examples will work without problems:
+
+```typescript
+const user = {
+ firstName: 'Mike',
+ pointsCount: 1000,
+};
+
+// Both type calls work
+doSomething(user);
+doSomething({ firstName: 'Bob', pointsCount: 1800 });
+```
+
+That said, TypeScript developers say “created a type” rather than “created a type alias”. So in this course we will stick to the commonly used format.
+
+Types can be specified for any data type, such as simple data types:
+
+```typescript
+type SomeType = string;
+```
+
+And also for composite:
+
+```typescript
+// Union type of three possible values
+type SomeType = string | number | null;
+
+// Function
+type Countable = (coll: number[]) => number
+```
+
+## Objects and functions
+
+The description of the function type outside the object and inside is different. When the function is written independently, the arrow function format is used:
+
+```typescript
+type Countable = (coll: number[]) => number
+```
+
+Inside a type that describes an object, the format changes to that used for normal properties:
+
+```typescript
+type User = {
+ firstName: string;
+ pointsCount: number;
+ count(coll: number[]): number;
+}
+```
+
+But that doesn't apply to the callbacks that can be used inside:
+
+```typescript
+type User = {
+ firstName: string;
+ pointsCount: number;
+ // Types are used as an example here
+ count(coll: (v: string) => string): number;
+}
+```
+
+In this lesson we learned how to use type aliases. We also learned how to set an alias for compound types.
\ No newline at end of file
diff --git a/modules/10-basics/70-type-aliases/en/data.yml b/modules/10-basics/70-type-aliases/en/data.yml
new file mode 100644
index 0000000..d2e8d11
--- /dev/null
+++ b/modules/10-basics/70-type-aliases/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Type Aliases
diff --git a/modules/10-basics/80-any/en/EXERCISE.md b/modules/10-basics/80-any/en/EXERCISE.md
new file mode 100644
index 0000000..ab0d289
--- /dev/null
+++ b/modules/10-basics/80-any/en/EXERCISE.md
@@ -0,0 +1,11 @@
+
+Implement the `getParams()` function that takes a query string as input and returns the parameters as an object:
+
+```typescript
+getParams('per=10&page=5');
+// { per: '10', page: '5' }
+getParams('name=hexlet&count=3&order=asc');
+// { name: 'hexlet', count: '3', order: 'asc' }
+```
+
+This task is best accomplished through the `reduce()` method.
\ No newline at end of file
diff --git a/modules/10-basics/80-any/en/README.md b/modules/10-basics/80-any/en/README.md
new file mode 100644
index 0000000..6aaf880
--- /dev/null
+++ b/modules/10-basics/80-any/en/README.md
@@ -0,0 +1,77 @@
+
+In this lesson, we'll break down the special type `any` that is added to TypeScript.
+
+## The usefulness of the `any` type
+
+The `any` type is used where type checking is not needed, or when TypeScript cannot derive the data type automatically:
+
+```typescript
+// In this case the type will be any[]
+// because TypeScript cannot infer its content
+// as it does not yet exist
+const items = [];
+// We can add anything we want
+items.push(1);
+items.push('code-basics');
+```
+
+`any` turns TypeScript into JavaScript, since data with that type is no longer validated:
+
+```typescript
+// The error will occur only when the JS code is running
+let value: any = 5;
+value.toString(); // ok
+value(); // ok, but will be an error if the JS code is executed
+value.trim(); // ok, but will be an error if the JS code is executed
+value = 'wow'; // ok
+```
+
+However, `any` is useful in many cases. For example, when you need to translate a project from JavaScript to TypeScript. In this case, all types are first declared as `any` and then rewritten to the required types.
+
+Also, `any` is used to work with JavaScript libraries from TypeScript code that do not have any described types. In other cases, `any` should be avoided, as it loses the whole point of using the TypeScript language.
+
+Let's consider the first case in more detail.
+
+## From JavaScript to TypeScript
+
+Let's take the code that counts the number of words in a sentence as an example:
+
+```javascript
+const sentence = 'table cat table dog dog apple table';
+
+const words = sentence.split(' ');
+const initial = {};
+const result = words.reduce((acc, word) => {
+ acc[word] = Object.hasOwn(acc, word) ? acc[word] + 1 : 1;
+ return acc;
+}, initial);
+// { table: 3, cat: 1, dog: 2, apple: 1 }
+```
+
+The TypeScript compiler will not allow such code. It will indicate that the object that is in the `initial` constant does not contain keys with string type:
+
+```
+No index signature with a parameter of type 'string' was found on type '{}'.
+4 acc[word] = Object.hasOwn(acc, word) ? acc[word] + 1 : 1;
+```
+
+This is so because the structure of an object specifies its type at definition time. Also, the structure cannot be changed during operation. But in the code above, the object is initially empty, but as it works, it is filled with keys dynamically.
+
+We will learn how to set the correct type in a situation with dynamic keys later. For now, let's make the code work using `any`. To do this, we need to define an object with an explicit type specification:
+
+```typescript
+const sentence = 'table cat table dog dog apple table';
+
+const words = sentence.split(' ');
+const initial: any = {}; // Set type as any
+const result = words.reduce((acc, word) => {
+ acc[word] = Object.hasOwn(acc, word) ? acc[word] + 1 : 1;
+ return acc;
+}, initial);
+```
+
+TypeScript no longer shows a compilation error, which is good on the one hand. But on the other hand, the validity check itself is disabled. If you later call a non-existent property in this object, TypeScript will not show an error.
+
+## Conclusions
+
+In this lesson we learned how to work with the `any` type. We also learned what it is used for and in what cases.
diff --git a/modules/10-basics/80-any/en/data.yml b/modules/10-basics/80-any/en/data.yml
new file mode 100644
index 0000000..f27a083
--- /dev/null
+++ b/modules/10-basics/80-any/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Type Any
+tips:
+ - >
+ [Official documentation about
+ any](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#any)
diff --git a/modules/10-basics/80-any/ru/README.md b/modules/10-basics/80-any/ru/README.md
index d687c9b..0cf7b05 100644
--- a/modules/10-basics/80-any/ru/README.md
+++ b/modules/10-basics/80-any/ru/README.md
@@ -18,15 +18,15 @@ items.push('code-basics');
`any` превращает TypeScript в JavaScript, так как данные с таким типом перестают проверяться:
```typescript
-// Ошибка возникнет только во время запуска js-кода
+// Ошибка возникнет только во время запуска JS-кода
let value: any = 5;
value.toString(); // ok
-value(); // ok, но будет ошибка при запуске js-кода
-value.trim(); // ok, но будет ошибка при запуске js-кода
+value(); // ok, но будет ошибка при запуске JS-кода
+value.trim(); // ok, но будет ошибка при запуске JS-кода
value = 'wow'; // ok
```
-Тем не менее, `any` полезен во многих случаях. Например, когда нужно перевести проект из JavaScript в TypeScript. В этом случае сначала все типы объявляются как `any`, а затем переписываются на нужные.
+Тем не менее `any` полезен во многих случаях. Например, когда нужно перевести проект из JavaScript в TypeScript. В этом случае сначала все типы объявляются как `any`, а затем переписываются на нужные.
Также `any` используют для работы с библиотеками JavaScript из TypeScript кода, у которых нет описанных типов. В остальных случаях `any` нужно избегать, так как теряется весь смысл использования языка TypeScript.
diff --git a/modules/10-basics/90-modules/en/EXERCISE.md b/modules/10-basics/90-modules/en/EXERCISE.md
new file mode 100644
index 0000000..639acc5
--- /dev/null
+++ b/modules/10-basics/90-modules/en/EXERCISE.md
@@ -0,0 +1,10 @@
+
+Implement namespace `Company` in which the `isEmployeeEmail()` function is exported. The function accepts an email and a domain. If the user's email contains the specified domain, the function returns `true`:
+
+```typescript
+Company.isEmployeeEmail('tirion@hexlet.io', 'hexlet.io');
+// true
+
+Company.isEmployeeEmail('user@example.com', 'hexlet.io');
+// false
+```
diff --git a/modules/10-basics/90-modules/en/README.md b/modules/10-basics/90-modules/en/README.md
new file mode 100644
index 0000000..bdaca14
--- /dev/null
+++ b/modules/10-basics/90-modules/en/README.md
@@ -0,0 +1,63 @@
+
+In this lesson, let's look at the TypeScript module system, which predates the standardization of ESM modules.
+
+By default, this module system is compatible with Node.js modules. It uses an identical algorithm for defining imports and exports, while being syntactically similar to ESM. In it, we use the `import`/`export` keywords to import into and export from the current module, while still validating the use of CommonJS modules.
+
+For the example, let's create two files. We will export the function from one and import it in the other:
+
+```typescript
+// @file helloWorld.ts
+export default function helloWorld() {
+ console.log("Hello, world!");
+}
+
+// @file main.ts
+import helloWorld from './helloWorld';
+```
+
+The TypeScript module system also supports named export/import and importing everything exported via `import * as`:
+
+```typescript
+// @file helloWorld
+export function helloWorld() {}
+export function helloWorldAgain() {}
+
+// @file main
+import { helloWorld, helloWorldAgain } from './helloWorld';
+
+// @file next
+import * as hw from './helloWorld';
+hw.helloWorld();
+```
+
+## Type import
+
+TypeScript uses npm packages for dependencies just like JavaScript. It is important to remember that some packages may not have types. For example, the `lodash` package has no types, so when importing its functions, TypeScript will crap on the lack of types.
+
+To solve this problem, you need to install the `@types/lodash` package, which contains the types for `lodash`.
+
+But the opposite is also true, for example, the `type-fest` package contains only types. To create such a package yourself and not accidentally import function implementations, you need to use a special syntax:
+
+```typescript
+// @file user.types.ts
+export type User = { name: string };
+
+// @file main.ts
+import type { User } from './user.types';
+```
+
+## Namespace
+
+The modules solve the problem of heterogeneous entities and collisions by spreading code across multiple files. To avoid collisions within a single file, the `namespace` mechanism is used:
+
+```typescript
+namespace Hello {
+ export function helloWorld() {
+ console.log("Hello, world!");
+ }
+}
+
+const helloWorld = Hello.helloWorld();
+```
+
+This mechanism is most useful for authors of libraries and wrappers with `@types/`. They enclose all interfaces in a single `namespace` that matches the library name. This ensures that there are no name collisions and makes it easy for users to merge interfaces. We'll talk about the latter point in one of the next lessons of the course.
diff --git a/modules/10-basics/90-modules/en/data.yml b/modules/10-basics/90-modules/en/data.yml
new file mode 100644
index 0000000..3bb3c4b
--- /dev/null
+++ b/modules/10-basics/90-modules/en/data.yml
@@ -0,0 +1,15 @@
+---
+name: Modules
+tips:
+ - >
+ [Official documentation
+ about modules](https://www.typescriptlang.org/docs/handbook/modules.html)
+ - >
+ [How module
+ resolution happens](https://www.typescriptlang.org/docs/handbook/module-resolution.html#how-nodejs-resolves-modules)
+ - >
+ [Official documentation
+ about namespaces](https://www.typescriptlang.org/docs/handbook/namespaces.html)
+ - >
+ [Method
+ includes()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)
diff --git a/modules/10-basics/90-modules/ru/EXERCISE.md b/modules/10-basics/90-modules/ru/EXERCISE.md
index 989c1d5..9766318 100644
--- a/modules/10-basics/90-modules/ru/EXERCISE.md
+++ b/modules/10-basics/90-modules/ru/EXERCISE.md
@@ -1,5 +1,5 @@
-Реализуйте namespace `Company`, в котором экспортируется функция `isEmployeeEmail()`. Функция принимает почту и домен. Если емейл пользователя содержит указанный домен, то функция возвращает `true`:
+Реализуйте namespace `Company`, в котором экспортируется функция `isEmployeeEmail()`. Функция принимает почту и домен. Если е-мейл пользователя содержит указанный домен, то функция возвращает `true`:
```typescript
Company.isEmployeeEmail('tirion@hexlet.io', 'hexlet.io');
diff --git a/modules/10-basics/90-modules/ru/README.md b/modules/10-basics/90-modules/ru/README.md
index f97f2ba..eba417d 100644
--- a/modules/10-basics/90-modules/ru/README.md
+++ b/modules/10-basics/90-modules/ru/README.md
@@ -32,7 +32,7 @@ hw.helloWorld();
## Импорт типов
-TypeScript также как и JavaScript использует npm-пакеты для зависимостей. При этом важно помнить, что в некоторых пакетах типов может и не быть. Например, в пакете `lodash` нет типов, поэтому при импорте его функций TypeScript будет ругаться на отсутствие типов.
+TypeScript так же как и JavaScript использует npm-пакеты для зависимостей. При этом важно помнить, что в некоторых пакетах типов может и не быть. Например, в пакете `lodash` нет типов, поэтому при импорте его функций TypeScript будет ругаться на отсутствие типов.
Для решения этой проблемы нужно установить пакет `@types/lodash`, который содержит типы для `lodash`.
diff --git a/modules/10-basics/description.en.yml b/modules/10-basics/description.en.yml
new file mode 100644
index 0000000..dce8f3c
--- /dev/null
+++ b/modules/10-basics/description.en.yml
@@ -0,0 +1,5 @@
+---
+name: TypeScript Fundamentals
+description: |
+ TypeScript is one of the most popular programming languages in the world. It is used to create interactive web pages, mobile applications, and in server-side development.
+ We will learn TS from scratch, from the very basics. The first module is a springboard for writing meaningful programs. In it, we will learn how to write your first code in TS. We will tell you what comments are and why you need them. On the example of checking your decisions, we will consider what testing is and how to read test output.
diff --git a/modules/20-functions/10-function-as-parameter/en/EXERCISE.md b/modules/20-functions/10-function-as-parameter/en/EXERCISE.md
new file mode 100644
index 0000000..b2575fd
--- /dev/null
+++ b/modules/20-functions/10-function-as-parameter/en/EXERCISE.md
@@ -0,0 +1,13 @@
+
+Implement a `filter()` function that takes an array of numbers and a predicate as input. The latter will be used to check each number for compliance:
+
+```typescript
+const numbers = [1, -5, 2, 3, 4, 133];
+filter(numbers, (n) => n > 3); // [4, 133]
+filter(numbers, (n) => n % 2 == 0); // [2, 4]
+```
+
+Function parameters:
+
+1. Array of numbers
+2. Anonymous function that takes a number as input and returns a logical value
\ No newline at end of file
diff --git a/modules/20-functions/10-function-as-parameter/en/README.md b/modules/20-functions/10-function-as-parameter/en/README.md
new file mode 100644
index 0000000..93998b8
--- /dev/null
+++ b/modules/20-functions/10-function-as-parameter/en/README.md
@@ -0,0 +1,71 @@
+
+TypeScript uses several ways to type functions that are passed as parameters. In this lesson, we will learn how to work with them.
+
+## How to type functions that are passed as parameters
+
+The easiest way to type functions as parameters is to use the `Function` type. It describes a JavaScript function with all its features, including the `bind`, `call` and `apply` properties.
+
+Let's describe the `callback` input parameter of the `process` function:
+
+```typescript
+function process(callback: Function) {
+ const value = callback();
+ // ...
+}
+```
+
+`Function` disables type checking for the called function. As a result, the number and type of input arguments are not checked, and the result of such a function will be `any`. This may cause logical errors and unexpected behavior:
+
+```typescript
+process(Math.round); // ?
+```
+
+This example will work, although the behavior is unlikely to be expected, since `Math.round` will be called without arguments and return `NaN`. We therefore recommend avoiding the use of `Function`.
+
+Another way to describe functions is to use an arrow function with input and output types:
+
+```typescript
+function process(callback: () => string) {
+ // value has type string
+ const value = callback();
+ // ...
+}
+
+process(Math.round);
+// Argument of type '(x: number) => number' is not
+// assignable to parameter of type '() => string'.
+```
+
+The definition of an arrow function is similar to the real one, but it is important not to get confused here. Here we see exactly a type description, not a function definition.
+
+Let's look at a few more examples to reinforce the knowledge:
+
+```typescript
+function process(callback: () => number)
+function process(callback: () => string[])
+function process(callback: () => { firstName: string; })
+```
+
+Parameters are syntactically specified in the same way as for arrow functions:
+
+```typescript
+function process(callback: (n: number) => string) {
+ const value = callback(10);
+ // ...
+}
+```
+
+Here we have defined a `callback` type function with parameter `n` with type `number` and return value `string`.
+
+If a function definition occurs frequently, you can create an alias for it:
+
+```typescript
+type myFunction = (n: number) => string;
+
+function process(callback: myFunction) {
+ const value = callback(10);
+ // ...
+}
+```
+
+Such an entry simplifies code reading and avoids duplication.
\ No newline at end of file
diff --git a/modules/20-functions/10-function-as-parameter/en/data.yml b/modules/20-functions/10-function-as-parameter/en/data.yml
new file mode 100644
index 0000000..2f677ec
--- /dev/null
+++ b/modules/20-functions/10-function-as-parameter/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Functions as parameters
+tips:
+ - >
+ [Functions in The TypeScript
+ Handbook](https://www.typescriptlang.org/docs/handbook/2/functions.html)
diff --git a/modules/20-functions/20-optional-parameters-in-callbacks/en/EXERCISE.md b/modules/20-functions/20-optional-parameters-in-callbacks/en/EXERCISE.md
new file mode 100644
index 0000000..a3f942a
--- /dev/null
+++ b/modules/20-functions/20-optional-parameters-in-callbacks/en/EXERCISE.md
@@ -0,0 +1,20 @@
+
+Implement the `map()` function. It should take as input an array of numbers and a callback, which will be used to convert each number in the array to another number. The function returns an array with new numbers:
+
+```typescript
+map([3, 9], (n) => n - 3);
+// [0, 6]
+
+map([8, 9], (n) => n + 8);
+// [16, 17]
+```
+
+Function parameters:
+
+1. Array of numbers
+2. Anonymous function that takes a number as input and returns a number. This function has an optional parameter - the index of the element in the array
+
+```typescript
+map([8, 9], (n, index) => index + n);
+// [8, 10]
+```
diff --git a/modules/20-functions/20-optional-parameters-in-callbacks/en/README.md b/modules/20-functions/20-optional-parameters-in-callbacks/en/README.md
new file mode 100644
index 0000000..16ee1ef
--- /dev/null
+++ b/modules/20-functions/20-optional-parameters-in-callbacks/en/README.md
@@ -0,0 +1,74 @@
+
+In this lesson, we'll break down optional parameters in functions.
+
+## Using optional parameters in functions
+
+Optional parameters in functions are used in JavaScript built-in functions when a parameter is optional. Optional parameters are specified with a question mark after the variable name before the colon.
+
+For example, the `split()` function splits a string into an array of strings by delimiter:
+
+```typescript
+function split(str: string, separator?: string)
+
+split('hexlet');
+split('hexlet,code-basics', ',');
+```
+
+In this case, the real type of the `separator` variable will be `string | undefined` (`string` or `undefined`).
+
+Another option to set an optional parameter is to assign a default value:
+
+```typescript
+// The question mark is no longer there, as there is a default value
+function split(str: string, separator: string = ',') {
+ // ...
+}
+
+split('hexlet');
+split('hexlet,code-basics', ',');
+```
+
+Developers try to apply this logic to the callbacks, but encounter errors. Let's analyze why this happens.
+
+## Callback functions
+
+Let's introduce the `filter()` function, which filters numeric arrays according to a passed predicate:
+
+```typescript
+// Optional parameter index
+function filter(coll: number[], callback: (arg: number, index?: number) => boolean) {
+ const result: number[] = [];
+ coll.forEach((n, index) => {
+ // Here it is passed to the callback
+ if (callback(n, index)) {
+ result.push(n);
+ }
+ });
+ return result;
+}
+```
+
+As in the built-in `filter()` method, in this function callback takes the index of the array element to be processed as the second parameter. Usually it is not used, but sometimes array filtering is done on the basis of indices. And in this situation it is specified. For this purpose, we have marked this parameter as optional.
+
+The problem with the definition above is that it doesn't work:
+
+```typescript
+// Will run without errors
+filter([1, 2], (n) => n > 1);
+// Object is possibly 'undefined'
+filter([1, 2], (n, index) => index > n);
+```
+
+In this case, the error indicates that, due to the optional nature within the callback, it could theoretically be undefined. However, logically, this cannot happen since the index is always defined.
+
+To solve this situation, we need to do away with optionality:
+
+```typescript
+function filter(coll: number[], callback: (arg: number, index: number) => boolean) {
+ // ...
+}
+```
+
+If a JavaScript function is called with more parameters than defined, the extra ones are ignored. TypeScript behaves in the same way. Callbacks with fewer parameters can always appear where they are expected with more parameters, provided the types of the common parameters match.
+
+In the example above, the function `(n) => n > 1` is passed as an argument and called as `callback(n, index)`. This causes `index` to be ignored, and no type errors occur.
\ No newline at end of file
diff --git a/modules/20-functions/20-optional-parameters-in-callbacks/en/data.yml b/modules/20-functions/20-optional-parameters-in-callbacks/en/data.yml
new file mode 100644
index 0000000..900503d
--- /dev/null
+++ b/modules/20-functions/20-optional-parameters-in-callbacks/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Optional parameters in functions
diff --git a/modules/20-functions/30-void/en/EXERCISE.md b/modules/20-functions/30-void/en/EXERCISE.md
new file mode 100644
index 0000000..a12e201
--- /dev/null
+++ b/modules/20-functions/30-void/en/EXERCISE.md
@@ -0,0 +1,24 @@
+
+Try defining the `forEach()` function for numbers on your own:
+
+```typescript
+forEach([1, 2, 3], (n) => console.log(n));
+// 1
+// 2
+// 3
+
+const result = [];
+forEach([1, 2, 3], (n) => result.push(n));
+// [1, 2, 3]
+```
+
+Function parameters:
+
+1. Array of numbers
+2. Anonymous function that takes a number as input and returns `void`. This function has an optional parameter - the index of the element in the array
+
+```typescript
+forEach([8, 9], (n, index) => console.log(index + n));
+// 8
+// 10
+```
diff --git a/modules/20-functions/30-void/en/README.md b/modules/20-functions/30-void/en/README.md
new file mode 100644
index 0000000..cd5f20f
--- /dev/null
+++ b/modules/20-functions/30-void/en/README.md
@@ -0,0 +1,68 @@
+
+In this lesson, we will look at the `void` type. It is specified as a return for functions that return nothing.
+
+## Using Void Type
+
+`void` is automatically printed when there is no `return` instruction inside the function, or it is empty:
+```typescript
+function noop() {
+ // inside is empty
+}
+```
+
+In JavaScript, such functions return `undefined`, but in TypeScript `void` and `undefined` are different types. They differ in contextual typing, and this happens because of the way JavaScript itself works. The most striking example is the `forEach()` method.
+
+The `forEach()` method does not use the data returned by the passed callback, which is called internally. It might be logical to define the return as `undefined`, but let's look at an example:
+
+```typescript
+const numbers = [1, 2, 3];
+const result = [];
+
+numbers.forEach((n) => result.push(n));
+```
+
+The `push()` method returns the new length of the array. If `forEach()` required the callback to return `undefined`, this code would cause a compilation error. It would have to be rewritten, for example, like this:
+
+```typescript
+// Now the callback returns nothing,
+// so the result of calling is undefined
+numbers.forEach((n) => {
+ result.push(n);
+});
+```
+
+To avoid writing such code, `void` was introduced. It allows you to return any data, but makes its use meaningless.
+
+We can define the type of the function that returns `void` and use it to type the variable:
+
+```typescript
+type VoidFunc = () => void;
+
+// The type of function is defined through the context
+// of assigning it to a variable with the VoidFunc type
+const f: VoidFunc = () => true;
+
+const v = f();
+```
+
+Although `f()` returns `true`, the variable `v` is of type `void`. This means that we cannot use it for anything other than assigning it to another variable of type `void`.
+
+There is a single situation where specifying `void` explicitly forbids a return from a function. This is the definition of a function outside the context of use, when its type is explicitly specified:
+
+```typescript
+function foo(): void {
+ return true; // Error!
+}
+
+const bar = function(): void {
+ return true; // Error!
+};
+```
+
+In this case, returning any value will result in a compilation error.
+
+Also, `void` is a JavaScript operator, so it's important not to get confused with it. It evaluates the expression that follows it and returns `undefined`:
+
+```typescript
+void 10 === undefined // true
+```
diff --git a/modules/20-functions/30-void/en/data.yml b/modules/20-functions/30-void/en/data.yml
new file mode 100644
index 0000000..da1cc9d
--- /dev/null
+++ b/modules/20-functions/30-void/en/data.yml
@@ -0,0 +1,9 @@
+---
+name: Type Void
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/basic-types.html#void)
+ - >
+ [void in TypeScript and
+ JavaScript](https://fettblog.eu/void-in-javascript-and-typescript/)
diff --git a/modules/20-functions/35-never/en/EXERCISE.md b/modules/20-functions/35-never/en/EXERCISE.md
new file mode 100644
index 0000000..4932e38
--- /dev/null
+++ b/modules/20-functions/35-never/en/EXERCISE.md
@@ -0,0 +1,2 @@
+
+Implement a `fail()` function that throws any exception. Write its return type explicitly.
diff --git a/modules/20-functions/35-never/en/README.md b/modules/20-functions/35-never/en/README.md
new file mode 100644
index 0000000..abed384
--- /dev/null
+++ b/modules/20-functions/35-never/en/README.md
@@ -0,0 +1,52 @@
+
+In this lesson, let's learn about the `never` type.
+
+## Using Never Type
+
+The `never` type is used when a function is guaranteed to return nothing. For example, if there is an infinite loop inside the function:
+
+```typescript
+function infiniteLoop(): never {
+ while (true) {
+ // Some logic
+ }
+}
+```
+
+We explicitly stated that the `infiniteLoop` function returns nothing.
+
+The `never` type is also used if a function throws an exception:
+
+```typescript
+function stop(message: string): never {
+ throw new Error(message);
+}
+```
+
+Also, the `never` type is used when the function terminates the program:
+
+```typescript
+function exit(code: number = 0): never {
+ process.exit(code);
+}
+```
+
+An important condition for `never` is that there is no normal termination of the function. For example, in the example below, the compiler will generate an error:
+
+```typescript
+// A function returning 'never' cannot have a reachable end point.
+function printSomething(): never {
+ console.log('hexlet');
+}
+```
+
+The `printSomething()` function returns nothing explicitly. But since it terminates in principle, JavaScript substitutes an implicit return of `undefined`.
+
+`never` is automatically output even where an explicit return is specified. But the compiler sees that this return is impossible:
+
+```typescript
+function fail() { // Automatically inferres never
+ // function exit, declared above, have never return type
+ return exit(1);
+}
+```
diff --git a/modules/20-functions/35-never/en/data.yml b/modules/20-functions/35-never/en/data.yml
new file mode 100644
index 0000000..29d2bf0
--- /dev/null
+++ b/modules/20-functions/35-never/en/data.yml
@@ -0,0 +1,5 @@
+---
+name: Never Type
+tips:
+ - |
+ [Never Type](https://basarat.gitbook.io/typescript/type-system/never)
diff --git a/modules/20-functions/40-unknown/en/EXERCISE.md b/modules/20-functions/40-unknown/en/EXERCISE.md
new file mode 100644
index 0000000..c75fe76
--- /dev/null
+++ b/modules/20-functions/40-unknown/en/EXERCISE.md
@@ -0,0 +1,10 @@
+
+Write the `isPlainObject()` function that checks if the passed value is an object. This function considers that the array is not an object:
+
+```typescript
+isPlainObject(1); // false
+isPlainObject('hexlet'); // false
+isPlainObject({}); // true
+isPlainObject({ name: 'code-basics' }); // true
+isPlainObject([1, 8]); // false
+```
diff --git a/modules/20-functions/40-unknown/en/README.md b/modules/20-functions/40-unknown/en/README.md
new file mode 100644
index 0000000..699ad24
--- /dev/null
+++ b/modules/20-functions/40-unknown/en/README.md
@@ -0,0 +1,48 @@
+
+Using `any` in TypeScript disables type checks, which is not desirable. Also, in the most strict mode with `“strict”: true` in `tsconfig.json`, using `any` is not possible. And this greatly increases the security of the code.
+
+At the same time, there are situations when a type is unknown, but you need to work with it in a type-safe way. For this purpose, TypeScript has an addition to `any` - `unknown`, which will be discussed in this lesson.
+
+## Using unknown type
+
+The main difference between `unknown` and `any` has to do with type checking. `unknown` prohibits performing any operations:
+
+```typescript
+let value: unknown = 'code-basics';
+
+value.toUpperCase(); // Error!
+value.trim(); // Error!
+```
+
+It may seem strange that we have a string here, but you can't perform string operations on it. This is something you have to get used to. The type in statically typed languages is determined not by what we see with our eyes, but by how the type is inferred - automatically or through explicit specification.
+
+The `unknown` type variable is rarely needed - when we need to specify the type further. But everything changes when we need to create a function that can work with any input type. This is a common practice in JavaScript:
+
+```typescript
+// Example from lodash
+_.isError(new Error); // true
+_.isError(Error); // false
+_.isError('code-basics'); // false
+```
+
+Such a function can be implemented with `any`, but then we will disable type checking:
+
+```typescript
+function isError(value: any)
+```
+
+It is better to use `unknown`, then TypeScript will protect us against potential type errors:
+
+```typescript
+function isError(value: unknown)
+```
+
+Then within the function body, we can do the necessary checking to see what we are working with:
+
+```typescript
+function isError(value: unknown): boolean {
+ return value instanceof Error;
+}
+```
+
+`instanceof` only works with constructors, so in the example above we are checking if the value is an instance of the `Error` class.
diff --git a/modules/20-functions/40-unknown/en/data.yml b/modules/20-functions/40-unknown/en/data.yml
new file mode 100644
index 0000000..c114539
--- /dev/null
+++ b/modules/20-functions/40-unknown/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Unknown Type
diff --git a/modules/20-functions/70-destructuring/en/EXERCISE.md b/modules/20-functions/70-destructuring/en/EXERCISE.md
new file mode 100644
index 0000000..91b5019
--- /dev/null
+++ b/modules/20-functions/70-destructuring/en/EXERCISE.md
@@ -0,0 +1,9 @@
+
+Implement a `lessonsCount()` function that takes a course as input and returns the number of lectures within it:
+
+```typescript
+const course = { lessons: ['intro', 'lala'] };
+lessonsCount(course); // 2
+```
+
+Use parameter destructuring to extract lessons directly in the function parameters.
\ No newline at end of file
diff --git a/modules/20-functions/70-destructuring/en/README.md b/modules/20-functions/70-destructuring/en/README.md
new file mode 100644
index 0000000..263053e
--- /dev/null
+++ b/modules/20-functions/70-destructuring/en/README.md
@@ -0,0 +1,75 @@
+
+In this lesson, let's break down destructuring in function definition.
+
+## Use of destructuring
+
+**Destructuring** is a mechanism by which an object passed as an argument is unpacked and its parts are assigned to local function variables. In JavaScript, it looks like this:
+
+```javascript
+// Usual definition
+const f = (user) => {
+ console.log(user.firstName, user.age);
+};
+
+// Destructured object
+const f = ({ firstName, age }) => {
+ console.log(firstName, age);
+};
+
+const user = { firstName: 'Smith', age: 30 };
+f(user); // => 'Smith', 30
+```
+
+A destructured object is visually similar to function parameters. However, it is still an object, so TypeScript describes its type after the closing curly brace:
+
+```typescript
+// Usual definition
+function f(user: { firstName: string, age: number }) {
+ console.log(user.firstName, user.age);
+}
+
+// Destructured object
+function f({ firstName, age }: { firstName: string, age: number }) {
+ console.log(firstName, age);
+}
+```
+
+Here we have described the object type inside a function parameter and immediately destructured it.
+
+If we put the type definition into an alias, you can make the code shorter:
+
+```typescript
+type User = {
+ firstName: string;
+ age: number;
+}
+
+function foo({ firstName, age }: User) {
+ console.log(firstName, age);
+}
+```
+
+The same `User` type will be able to be used elsewhere.
+
+The same applies to arrays:
+
+```typescript
+// Usual definition
+function foo(point: number[]) {
+ console.log(point);
+}
+
+// Destructured array
+function foo([x, y]: number[]) {
+ console.log(x, y);
+}
+
+type Point = number[];
+
+// With an alias
+function foo([x, y]: Point) {
+ console.log(x, y);
+}
+```
+
+Using destructuring is convenient when you need to use several object properties or array elements inside a function. In this case, you can immediately extract them in the function parameters, instead of writing `user.firstName` or `point[0]` inside the function body.
\ No newline at end of file
diff --git a/modules/20-functions/70-destructuring/en/data.yml b/modules/20-functions/70-destructuring/en/data.yml
new file mode 100644
index 0000000..1d99ef7
--- /dev/null
+++ b/modules/20-functions/70-destructuring/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Destructuring
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/2/functions.html#parameter-destructuring)
diff --git a/modules/20-functions/80-rest-spread/en/EXERCISE.md b/modules/20-functions/80-rest-spread/en/EXERCISE.md
new file mode 100644
index 0000000..be61b19
--- /dev/null
+++ b/modules/20-functions/80-rest-spread/en/EXERCISE.md
@@ -0,0 +1,9 @@
+
+Define the `max()` function, which differs from the example in the lesson only in that its first parameter is mandatory.
+
+For example:
+
+```typescript
+max(1,2,3);
+max(234);
+```
diff --git a/modules/20-functions/80-rest-spread/en/README.md b/modules/20-functions/80-rest-spread/en/README.md
new file mode 100644
index 0000000..c437830
--- /dev/null
+++ b/modules/20-functions/80-rest-spread/en/README.md
@@ -0,0 +1,54 @@
+
+Today we'll look at rest- and spread-operators.
+
+## Rest Operator
+
+The Rest operator allows you to create functions with a variable number of parameters, while collapsing them into an array:
+
+```typescript
+function max(...numbers: number[]): number {
+ return Math.max(...numbers);
+}
+```
+
+This array is a normal function parameter, so it is given a type according to what values are expected within this array. Example with two parameters:
+
+```typescript
+function do(operation: string, ...numbers: number[]) {
+ // perform operation on all array members
+}
+```
+
+In this sense, the rest operator in TypeScript is no different from the rest operator in JavaScript. But there is one peculiarity with the spread operator.
+
+## Spread Operator
+
+Spread-оператор в функциях — это как rest-оператор наоборот. Он позволяет раскладывать массив на отдельные параметры:
+
+```typescript
+const numbers = [1, 2, 3];
+Math.max(...numbers);
+```
+
+Если функция принимает на вход любое количество аргументов, как в примере выше, то такой код работает без проблем. Но если функция принимает на вход определенное число аргументов, то TypeScript выдаст ошибку компиляции:
+
+```typescript
+function sum(a: number, b: number): number {
+ return a + b;
+}
+
+// Выведенный тип number[] — "ноль или больше чисел",
+// а не "массив из двух чисел"
+const args = [1, 2];
+sum(...args);
+// A spread argument must either have a tuple type
+// or be passed to a rest parameter.
+```
+
+В примере выше TypeScript не может понять, что массив `args` состоит из двух чисел. Массивы в JavaScript изменяемы, поэтому TypeScript не может полагаться на количество элементов в конкретный момент времени. Есть разные способы обойти это ограничение. Но в этой ситуации проще использовать Type Assertion — указание компилятору, что мы точно знаем о коде:
+
+```typescript
+const args = [1, 2] as const;
+```
+
+Подробнее о Type Assertion поговорим в модуле о типах. С его помощью мы явно указываем, что этот массив состоит из двух конкретных значений, которые не поменяются.
diff --git a/modules/20-functions/80-rest-spread/en/data.yml b/modules/20-functions/80-rest-spread/en/data.yml
new file mode 100644
index 0000000..4bf5aba
--- /dev/null
+++ b/modules/20-functions/80-rest-spread/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Rest and Spread
diff --git a/modules/20-functions/85-function-overloads/en/EXERCISE.md b/modules/20-functions/85-function-overloads/en/EXERCISE.md
new file mode 100644
index 0000000..bee3cf1
--- /dev/null
+++ b/modules/20-functions/85-function-overloads/en/EXERCISE.md
@@ -0,0 +1,7 @@
+
+Implement the `newYearCongratulate()` function, which is similar to the Kotlin example from theory:
+
+```typescript
+newYearCongratulate('John'); // Hi John! Happy New Year!
+newYearCongratulate(2023, 'Mila'); // Hi Mila! Happy New Year 2023!
+```
diff --git a/modules/20-functions/85-function-overloads/en/README.md b/modules/20-functions/85-function-overloads/en/README.md
new file mode 100644
index 0000000..c6fcb2a
--- /dev/null
+++ b/modules/20-functions/85-function-overloads/en/README.md
@@ -0,0 +1,102 @@
+
+In this lesson, we will learn how to use function overloads.
+
+## Using function overloads
+
+**Function Overload** — is the possibility to define several versions of one function, each of which accepts a different set of parameters. Let's look at an example:
+
+```typescript
+function concat(a: number, b: number): string;
+function concat(a: string, b: string): string;
+
+function concat(a: unknown, b: unknown): string {
+ if (typeof a === 'number' && typeof b === 'number') {
+ return `${a.toFixed()}${b.toFixed()}`;
+ }
+
+ return `${a}${b}`;
+}
+
+concat('one', 'two'); // onetwo
+concat(3, 5.34); // 35
+concat(1.33, 10); // 110
+```
+
+One function `concat()` is defined here. It has two versions that perform concatenation, but do it in different ways:
+
+* The first version accepts two numbers as input. The numbers first have the fractional part discarded, then they are concatenated;
+* Second version takes two strings as input. The strings are concatenated at once.
+
+The implementation of behavior for both versions is done in a third function with the same name. The description of parameters must be suitable for each version of the function. In the example above, the parameter types are defined as `unknown`. This makes it possible to call the function with both strings and numbers.
+
+Which branch to follow is determined by type checking. In the example above, it is enough to check the type of the first parameter only, because the second parameter will definitely be a string. This is provided by the type system and the compiler.
+
+You don't necessarily need to use a function declaration for overloading. The same can be done with an arrow function:
+
+```typescript
+const concat: {
+ (a: number, b: number): string;
+ (a: string, b: string): string;
+} = (a, b) => {
+ if (typeof a === 'number' && typeof b === 'number') {
+ return `${a.toFixed()}${b.toFixed()}`;
+ }
+
+ return `${a}${b}`;
+}
+
+// with using aliases
+type Overloaded = {
+ (a: number, b: number): string;
+ (a: string, b: string): string;
+}
+
+const concat: Overloaded = (a, b) => {...}
+```
+
+In this case, it is not necessary to explicitly specify the types of parameters inside the function.
+
+Function overloading is not limited to two versions. There can be as many of them as you like. The main thing is that a function is always described at the end, which is common in parameters for all variants and within which all logic for each variant is described.
+
+Let's describe the `add()` function, which can take two or three numbers as input and returns their sum:
+
+```typescript
+function add(a: number, b: number, c: number): number;
+function add(a: number, b: number): number;
+function add(a: string, b: string): string;
+
+// The signature fits all the examples above
+function add(a: unknown, b: unknown, c?: number): unknown {
+ // code logic here
+ if (c === undefined) {
+ // ...
+ }
+}
+```
+
+Function overloading is used quite often in static languages, but in most of them it is not organized like in TypeScript. In these languages, several different functions are created, which from the programmer's point of view have the same name. Therefore, there is no need for a common function there. The logic of each variant is described internally. This saves the code from having to implement conditional logic.
+
+```kotlin
+// Example from Kotlin
+fun main() {
+ fun newYearCongratulate (name:String):String {
+ return "Hi ${name}! Happy New Year!"
+ }
+ fun newYearCongratulate (year: Number, name:String):String {
+ return "Hi ${name}! Happy New Year ${year}!"
+ }
+
+ println(newYearCongratulate("John")) // Hi John! Happy New Year!
+ println(newYearCongratulate(2023, "Elon")) // Hi Elon! Happy New Year 2023!
+}
+```
+
+Why does TypeScript have this implementation and what problems do it solve? It's like many other things in TypeScript - it's an attempt to account for all variants of writing JavaScript code and cover them with types to write type-safe code.
+
+In JavaScript, it is not uncommon to create functions that take different data types as input in different variations. Function overloading allows such functions to be described in TypeScript, otherwise you would have to use `any` and keep track of the types yourself.
+
+Technically, after transpilation, there is one function left in JavaScript - the one that contains the body.
+
+Function overloading in TypeScript is a mechanism worth using when there is no other choice. In most cases, unions or generics are used instead of overloading, which we'll talk about later.
+
+Overloading is needed when there is a dependency between parameters, for example if both parameters are strings or both parameters are numbers.
\ No newline at end of file
diff --git a/modules/20-functions/85-function-overloads/en/data.yml b/modules/20-functions/85-function-overloads/en/data.yml
new file mode 100644
index 0000000..bb372c8
--- /dev/null
+++ b/modules/20-functions/85-function-overloads/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Function Overloads
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads)
diff --git a/modules/20-functions/85-function-overloads/ru/README.md b/modules/20-functions/85-function-overloads/ru/README.md
index 6d35bfc..1b6f46b 100644
--- a/modules/20-functions/85-function-overloads/ru/README.md
+++ b/modules/20-functions/85-function-overloads/ru/README.md
@@ -91,7 +91,7 @@ fun main() {
}
```
-Зачем в TypeScript такая реализация и какие проблемы она решает? Это как и многое другое в TypeScript — попытка учесть все варианты написания кода на JavaScript и покрыть их типами для написания типобезопасного кода.
+Зачем в TypeScript такая реализация и какие проблемы она решает? Это, как и многое другое в TypeScript — попытка учесть все варианты написания кода на JavaScript и покрыть их типами для написания типобезопасного кода.
В JavaScript нередко создают функции, которые принимают на вход разные типы данных в разных вариациях. Перегрузка функций позволяет описать подобные функции в TypeScript, иначе пришлось бы использовать `any` и следить за типами самостоятельно.
diff --git a/modules/20-functions/90-type-narrowing/en/EXERCISE.md b/modules/20-functions/90-type-narrowing/en/EXERCISE.md
new file mode 100644
index 0000000..85b9696
--- /dev/null
+++ b/modules/20-functions/90-type-narrowing/en/EXERCISE.md
@@ -0,0 +1,12 @@
+
+Implement the `last()` function that extracts the last element from the passed value. The value can be a string or a number. The function returns a value of the same type that was passed as a parameter:
+
+```typescript
+// Pass a string as a parameter
+// The function returns a string
+last('hexlet'); // t
+
+// Pass a number as a parameter
+// The function returns a number
+last(12345); // 5
+```
diff --git a/modules/20-functions/90-type-narrowing/en/README.md b/modules/20-functions/90-type-narrowing/en/README.md
new file mode 100644
index 0000000..ce0fcfc
--- /dev/null
+++ b/modules/20-functions/90-type-narrowing/en/README.md
@@ -0,0 +1,123 @@
+
+In this lesson, we will learn about type narrowing.
+
+## Using type narrowing
+
+In JavaScript, it is common to encounter code that may contain values of different types in the same variables. These are handled based on logical checks using `typeof` and other similar mechanisms.
+
+Below is an example implementation of a function that converts any passed value to `boolean`:
+
+```typescript
+function isPresence(value: unknown): boolean {
+ if (value === null || value === undefined) {
+ return false;
+ }
+ // empty string
+ if (typeof value === 'string') {
+ if (value === '') {
+ return false;
+ }
+ }
+ // empty array
+ if (Array.isArray(value)) {
+ if (value.length === 0) {
+ return false;
+ }
+ }
+ // empty object
+ if (value instanceof Object) {
+ if (Object.keys(value).length === 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+isPresence(''); // false
+isPresence({}); // false
+isPresence([]); // false
+isPresence([1, 3]); // true
+isPresence(10); // true
+```
+
+In this code, the parameter is of type `unknown`. Internally, TypeScript allows you to perform different actions with this parameter. They will depend on the given conditions.
+
+In this case, the type checking is done statically before the code is executed. And the conditions inside the function are a part of the code that is executed at runtime. It turns out that this code should end with an error, but it doesn't.
+
+Since such code is common in JavaScript, the TypeScript type system had to be modified so that it would still be possible to write such code.
+
+In this case, it turns out that TypeScript is able to execute some of the conditional constructs statically, as a type compatibility check, without running the code. Then, inside the conditional block, the compiler assumes that the type of the value matches what was in the check itself. This process in TypeScript is called **Type Narrowing** - type narrowing.
+
+Type narrowing doesn't just work for the `unknown` type. It is a universal mechanism that works with all possible types, such as Union Types:
+
+```typescript
+function foo(value: number | string) {
+ if (typeof value === 'number') {
+ // Processed like a number
+ }
+ if (typeof value === 'string') {
+ // Processed like a string
+ }
+}
+```
+
+`switch` also supports type narrowing:
+
+```typescript
+function foo(value: number | string) {
+ switch (typeof value) {
+ case 'number':
+ // some kind of logic
+ break;
+ case 'string':
+ // some kind of logic
+ break;
+ }
+}
+```
+
+Within each `case` block, the type of the value is narrowed down to what was in the `case` itself.
+
+Function overloading in TypeScript is also an example of how type narrowing works:
+
+```typescript
+function concat(a: number, b: number): string;
+function concat(a: string, b: string): string;
+
+function concat(a: any, b: any): string {
+ if (typeof a === 'string') {
+ return `${a}${b}`; // (parameter) a: string
+ } else {
+ return `${a.toFixed()}${b.toFixed()}`;
+ }
+}
+```
+
+## Type Guard
+
+In the examples, we used `typeof` for type checking. This is a special case of a **type guard**.
+
+We can also define our own type guards using a function and the `is` keyword. Let's write a function that checks that the passed value is an object:
+
+```typescript
+function isObject(value: unknown): value is object {
+ return typeof value === 'object' && value !== null;
+}
+```
+
+Here we use the `is` keyword to indicate that the passed value is an object. Inside the function, we must return `true` or `false`. In our example, we specify the return type as `value is object`. This means that we are asserting that `value` is an object. Such a notation also allows us to narrow down types.
+
+```typescript
+function isObject(value: unknown): value is object {
+ return typeof value === 'object' && value !== null;
+}
+
+function foo(value: unknown) {
+ if (isObject(value)) {
+ // (parameter) value: object
+ }
+}
+```
+
+Type narrowing is a big topic with many nuances. It is often found in TypeScript, so you will be able to deal with it in constant practice. You can read more about the peculiarities of this mechanism in the documentation - link at the end of the lesson.
diff --git a/modules/20-functions/90-type-narrowing/en/data.yml b/modules/20-functions/90-type-narrowing/en/data.yml
new file mode 100644
index 0000000..2ff0f40
--- /dev/null
+++ b/modules/20-functions/90-type-narrowing/en/data.yml
@@ -0,0 +1,8 @@
+---
+name: Type Narrowing
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/2/narrowing.html)
+ - |
+ [Type Guard](https://basarat.gitbook.io/typescript/type-system/typeguard)
diff --git a/modules/20-functions/description.en.yml b/modules/20-functions/description.en.yml
new file mode 100644
index 0000000..98c009c
--- /dev/null
+++ b/modules/20-functions/description.en.yml
@@ -0,0 +1,4 @@
+---
+name: Function typing
+description: |
+ Most of the tasks of function typing are related to the correct description of input parameters and return values, which can be quite complex. This also includes peculiarities of working with rest and destructuring.
diff --git a/modules/22-arrays/20-type-annotations/en/EXERCISE.md b/modules/22-arrays/20-type-annotations/en/EXERCISE.md
new file mode 100644
index 0000000..a109d16
--- /dev/null
+++ b/modules/22-arrays/20-type-annotations/en/EXERCISE.md
@@ -0,0 +1,8 @@
+
+Implement the `unique()` function that removes duplicates from an array. The function accepts an array of numbers and strings as input. The result of the function should be a new array in which only the first occurrence of each element is stored. The order of the result values is determined by the order of their occurrence in the array.
+
+```typescript
+unique([9, 9, 3, 8, 8]); // [9, 3, 8]
+unique(['twinkle', 'twinkle', 'little', 'bat']); // ['twinkle', 'little', 'bat']
+unique([1, 1, 3, 'oops!']); // [1, 3, 'oops!']
+```
diff --git a/modules/22-arrays/20-type-annotations/en/README.md b/modules/22-arrays/20-type-annotations/en/README.md
new file mode 100644
index 0000000..77fbb9e
--- /dev/null
+++ b/modules/22-arrays/20-type-annotations/en/README.md
@@ -0,0 +1,62 @@
+
+In this lesson, we will learn how to use type annotations.
+
+## Using type annotations
+
+In simple cases, the array type is defined as the type name and square brackets after it, e.g.: `string[]`, `number[]`. This scheme works with type aliases as well:
+
+```typescript
+type User = {
+ name: string
+};
+
+// When defining constants and variables
+const users: User[] = [];
+
+// In function definition
+function foo(users: User[]) {
+ // ...
+}
+```
+
+Here, we define an array whose elements are objects of `User` type. In such an array we can store only objects that correspond to the `User` type.
+
+In case of composite types, for example, if we want to use union or description of an object, we add parentheses - `(Type)[]`:
+
+```typescript
+const users: ({ name: string })[] = [];
+const users: (string | null)[] = [];
+const users: (User | null | { name: string })[] = [];
+```
+
+Inside the parentheses is a description of the type, followed by square brackets.
+
+TypeScript also provides another syntax, which is described as `Array`. It is universal - you can use it to describe any array. The type is described in this entry between the less and greater signs:
+
+```typescript
+const users: Array = [];
+const users: Array = [];
+const users: Array = [];
+
+const users: Array<{ name: string }> = [];
+const users: Array = [];
+```
+
+But usually this syntax is not used. The shorter version is used when it's possible. The `Array` form is needed primarily for generics, which we will consider later.
+
+## Defining an empty array
+
+If you define an empty array and do not specify a type, its type will automatically become `any[]`. Any data can be added to such an array, including nested arrays:
+
+```typescript
+const items = [];
+items.push(1);
+items.push('wow');
+items.push(['code-basics', 'hexlet']);
+```
+
+The code with `any` will always work, but it turns off type checking. To avoid this, you should always explicitly type an empty array:
+
+```typescript
+const items: Array = [];
+```
diff --git a/modules/22-arrays/20-type-annotations/en/data.yml b/modules/22-arrays/20-type-annotations/en/data.yml
new file mode 100644
index 0000000..c287ee4
--- /dev/null
+++ b/modules/22-arrays/20-type-annotations/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Type annotations
+tips:
+ - >
+ [Official documentation
+ about arrays](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#arrays)
diff --git a/modules/22-arrays/25-multi-dimensional-arrays/en/EXERCISE.md b/modules/22-arrays/25-multi-dimensional-arrays/en/EXERCISE.md
new file mode 100644
index 0000000..a1df439
--- /dev/null
+++ b/modules/22-arrays/25-multi-dimensional-arrays/en/EXERCISE.md
@@ -0,0 +1,12 @@
+
+Implement the `getField()` function that generates a game field for tic-tac-toe. The function takes the field dimension as input and returns an array of arrays of the required size filled with `null` values.
+
+```typescript
+const field1 = getField(1);
+console.log(field1);
+// [[null]]
+
+const field2 = getField(2);
+console.log(field2);
+// [[null, null], [null, null]]
+```
diff --git a/modules/22-arrays/25-multi-dimensional-arrays/en/README.md b/modules/22-arrays/25-multi-dimensional-arrays/en/README.md
new file mode 100644
index 0000000..4eb710f
--- /dev/null
+++ b/modules/22-arrays/25-multi-dimensional-arrays/en/README.md
@@ -0,0 +1,60 @@
+
+In this lesson, we will look at multidimensional arrays.
+
+## Working with multidimensional arrays
+
+To define multidimensional arrays, we need to use the `Type[][]` syntax. Literally, this means that we have an array in front of us that contains arrays with values of type `Type`. Some examples:
+
+```typescript
+// Type number[][] will be inferred automatically
+const items1 = [[3, 8], [10, 4, 8]];
+
+const items2: number[][] = []
+// or with Array
+
+// Using type alias
+type User = {
+ name: string;
+}
+
+// or with Array
+const users: User[][] = [
+ [{ name: 'Eva'}, { name: 'Adam' }],
+];
+```
+
+Adding non-arrays to such arrays will cause a typing error:
+
+```typescript
+items1.push(99); // Error: Type 'number' is not assignable
+```
+
+To define arrays of composite types, you must use parentheses:
+
+```typescript
+const coll: (string | number)[][] = [];
+coll.push(['hexlet', 5])
+```
+
+You can also use the `Array>` syntax. The example below is an array with arrays containing values of type `Type` inside:
+
+```typescript
+const coll: Array> = [];
+coll.push(['hexlet', 5])
+```
+
+Arrays themselves can be part of an object. Technically it allows creating infinite nesting of objects and arrays:
+
+```typescript
+type Course = {
+ name: string;
+ lessons: Lesson[];
+}
+
+type Lesson = {
+ name: string;
+ links: string[];
+}
+```
+
+Here we define the `Course` type, which contains an array of `lessons`. Each element of this array is an object of type `Lesson`, which contains an array of `links`. Each element of this array is a string. This data structure can be useful, for example, for storing information about courses on the website.
diff --git a/modules/22-arrays/25-multi-dimensional-arrays/en/data.yml b/modules/22-arrays/25-multi-dimensional-arrays/en/data.yml
new file mode 100644
index 0000000..26dc750
--- /dev/null
+++ b/modules/22-arrays/25-multi-dimensional-arrays/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Multidimensional arrays
diff --git a/modules/22-arrays/40-readonly-arrays/en/EXERCISE.md b/modules/22-arrays/40-readonly-arrays/en/EXERCISE.md
new file mode 100644
index 0000000..648f395
--- /dev/null
+++ b/modules/22-arrays/40-readonly-arrays/en/EXERCISE.md
@@ -0,0 +1,7 @@
+
+Implement the `reverse()` function that flips an array. Technically, it should return a new array with the elements in reverse order. Use the `readonly` modifier for the incoming array. Do not use the built-in `reverse()` method.
+
+```typescript
+reverse([1, 2, 8]); // [8, 2, 1]
+reverse([10, 33, 7, 0]); // [0, 7, 33, 10]
+```
diff --git a/modules/22-arrays/40-readonly-arrays/en/README.md b/modules/22-arrays/40-readonly-arrays/en/README.md
new file mode 100644
index 0000000..c314e10
--- /dev/null
+++ b/modules/22-arrays/40-readonly-arrays/en/README.md
@@ -0,0 +1,33 @@
+
+In JavaScript development, where higher-order functions such as `map`, `filter` and `reduce` are heavily used, arrays are rarely changed. Usually new ones are created instead.
+
+Technically, JavaScript cannot forbid changing existing arrays, so it is the responsibility of the programmer to enforce this rule. In this tutorial, we'll look at working with read-only arrays.
+
+## Using immutable arrays
+
+In TypeScript, working with immutable arrays is built into the type system. To guarantee immutability, an array is marked with the `readonly` modifier:
+
+```typescript
+function process(numbers: readonly number[]) {
+ numbers.push(1); // Error!
+}
+```
+
+In this case, TypeScript returns the error that the `readonly number[]` type does not contain a `push` method.
+
+The `readonly` modifier prohibits modification of an array, but does not prohibit modification of objects that are inside the array:
+
+```typescript
+const items: readonly ({ key: string })[] = [{ key: 'value'}];
+items[0].key = 'another value'; // ok!
+```
+
+We have successfully modified the value of the `key` property in an object that is inside an array.
+
+The `readonly` modifier is syntactic sugar. In the case of an array, `readonly` changes the type of `Array` to the type `ReadonlyArray`. Such a record as `Array` improves code readability, but otherwise does not differ from `readonly Type[]`.
+
+The code above could be written like this:
+
+```typescript
+const items: ReadonlyArray<{ key: string }> = [{ key: 'value'}];
+```
diff --git a/modules/22-arrays/40-readonly-arrays/en/data.yml b/modules/22-arrays/40-readonly-arrays/en/data.yml
new file mode 100644
index 0000000..3fc283a
--- /dev/null
+++ b/modules/22-arrays/40-readonly-arrays/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Readonly arrays
+tips:
+ - >
+ [Read-Only Array and
+ Tuple Types in TypeScript](https://mariusschulz.com/blog/read-only-array-and-tuple-types-in-typescript/)
diff --git a/modules/22-arrays/50-tuples/en/EXERCISE.md b/modules/22-arrays/50-tuples/en/EXERCISE.md
new file mode 100644
index 0000000..5494fb7
--- /dev/null
+++ b/modules/22-arrays/50-tuples/en/EXERCISE.md
@@ -0,0 +1,14 @@
+
+Create and export a `Point` type that describes a point in space consisting of three coordinates: x, y, z.
+
+Implement the `isTheSamePoint()` function that checks two points to see if they are the same. Two points are the same if all their coordinates match:
+
+```typescript
+const p1: Point = [1, 3, 4];
+const p2: Point = [1, 3, 4];
+const p3: Point = [0, 8, 4];
+
+isTheSamePoint(p1, p2); // true
+isTheSamePoint(p1, p3); // false
+isTheSamePoint(p2, p3); // false
+```
diff --git a/modules/22-arrays/50-tuples/en/README.md b/modules/22-arrays/50-tuples/en/README.md
new file mode 100644
index 0000000..f9e485b
--- /dev/null
+++ b/modules/22-arrays/50-tuples/en/README.md
@@ -0,0 +1,63 @@
+
+Usually, arrays can change their size and contain any number of values starting with zero. Therefore, an empty array as a `[]` value is valid for arrays of any type.
+
+At the same time, sometimes arrays act as a simplified version of an object, where the number of values and their order are strictly defined. For example, you can use such an array to represent a point on the surface: `[x, y]`.
+
+Such arrays are needed to save characters when you have to create a lot of identical data, such as for testing.
+
+In TypeScript, such arrays are called tuples, which we will learn about in this lesson.
+
+## Using tuples
+
+Tuples have their own definition syntax. For example, consider the representation of a point:
+
+```typescript
+const point: [number, number] = [1, 3]
+// Can be changed
+const point[0] = 4;
+
+// Accessing a non-existent index will result in an error
+point[3]; // Error!
+
+// Can't create a non-matching type
+const point2: [number, number] = [1, 'x']; // Error!
+```
+
+Since tuples have a fixed number of elements, it would make sense if the same behaviour applied to `push()` or `pop()`. After all, if we have defined a tuple of two elements, there should be exactly two elements.
+
+In practice, the code below will work:
+
+```typescript
+point.push(10);
+console.log(point); // [4, 3, 10];
+```
+
+This behavior persists for [backwards compatibility](https://stackoverflow.com/questions/64069552/typescript-array-push-method-cant-catch-a-tuple-type-of-the-array). And the general recommendation is not to try to change the size of a tuple.
+
+Tuples may consist of elements of different types:
+
+```typescript
+type HTTPResponse = [number, string];
+
+// The order of definition is important
+const response: HTTPResponse = [404, 'Page is not found'];
+// This won't work ['Page is not found', 404]
+```
+
+Some of them may be optional. In this case, the optional elements must be at the end of the tuple:
+
+```typescript
+type HTTPResponse = [number, string?];
+
+const response1: HTTPResponse = [500];
+const response2: HTTPResponse = [201, 'Created'];
+```
+
+In the example above, the first element of the array must always be a number and the second element must always be a string or may be missing.
+
+If you create variables for tuples and use an alias, you must specify it explicitly. Otherwise, from a TypeScript point of view, an ordinary array will be created:
+
+```typescript
+// Will have (string | number)[] type
+const response = [201, 'Created'];
+```
diff --git a/modules/22-arrays/50-tuples/en/data.yml b/modules/22-arrays/50-tuples/en/data.yml
new file mode 100644
index 0000000..6da2c6a
--- /dev/null
+++ b/modules/22-arrays/50-tuples/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Tuples
+tips:
+ - >
+ [Official documentation
+ about tuples](https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types)
diff --git a/modules/22-arrays/description.en.yml b/modules/22-arrays/description.en.yml
new file mode 100644
index 0000000..06ca6e3
--- /dev/null
+++ b/modules/22-arrays/description.en.yml
@@ -0,0 +1,4 @@
+---
+name: Array typing
+description: |
+ Working with arrays in some cases requires more precise typing. In this module, we will look at the features of array typing: arrays containing elements of different types, multidimensional arrays, and fixed-length arrays.
diff --git a/modules/25-types/10-type-as-sets/en/EXERCISE.md b/modules/25-types/10-type-as-sets/en/EXERCISE.md
new file mode 100644
index 0000000..cd22f9e
--- /dev/null
+++ b/modules/25-types/10-type-as-sets/en/EXERCISE.md
@@ -0,0 +1,6 @@
+
+Define `CustomType`, which can take these values:
+
+1. null
+2. undefined
+3. number
diff --git a/modules/25-types/10-type-as-sets/en/README.md b/modules/25-types/10-type-as-sets/en/README.md
new file mode 100644
index 0000000..b49777b
--- /dev/null
+++ b/modules/25-types/10-type-as-sets/en/README.md
@@ -0,0 +1,35 @@
+
+In this lesson, we will learn about data types and how they are useful for a developer. We will also talk about types as sets. This will allow us to understand the principles of TypeScript.
+
+## Data Types
+
+A family of languages that doesn't have data types is called assembly languages. These languages work directly with the processor and operate on its registers. The registers store values, which from the language's point of view are numbers. It is up to the programmer to determine what is encoded behind this number. It can be a string or a part of a picture.
+
+The main problem of this approach is the lack of security. The program will not generate an error if we accidentally do something with the string that we cannot do. From the point of view of the processor and programming language, there is no string - there is a number, and we perform some operations on it. As a result, the program always works, but the result is incorrect. In this case, you need a high level of attention to program in this mode.
+
+The situation was corrected when data types appeared in high-level languages. They made it possible to fulfil two tasks:
+
+* Describe and restrict the set of all values of a particular type
+* Define the operations that can be performed on this type
+
+** A data type** is a set of all values and a set of allowed operations on them. With the help of types we impose restrictions on the code. For example, if we want to work with numbers, we need to use operations of addition, subtraction, etc. If we want to work with strings, we need to use operations of concatenation, substring search, etc. This approach avoids errors that can occur when working with data at runtime.
+
+Even in a dynamic language like JavaScript, we have types, and we get stronger security than in assembly language where data is just a sequence of bits. In TypeScript, we can set more complex constraints on the data, thus getting even stronger security.
+
+## Sets
+
+If we talk about data types as a set of allowed values, on the one hand, it can be a number constraint on upper and lower bounds. For example, this is how it works in JavaScript. We have `Number` for one range of numbers and `BigInt` for another when we need to work with huge numbers. On the other hand, we're talking about sets.
+
+Looking at types as sets plays an important role. This is because TypeScript's type system allows us to combine types in a way that is similar to that of regular sets. For example, we can combine two sets of types and get a new type that includes all the elements of the first set and the second set. This is how Union Type comes into being:
+
+```typescript
+type SomeType = number | string;
+const v1: SomeType = 1;
+const v2: SomeType = 'hexlet';
+```
+
+Here we have defined a type `SomeType`, which can take values of type `number` or `string`, and hence is the union of the sets of all numbers and strings.
+
+
+
+You can build intersection and extension types and do other things with types in roughly the same way. We'll cover some of them in the course, but some things will be left out. The main thing is that you need to reframe your thinking about operations with types. This will make it easier to understand the principles of TypeScript and remember certain behaviors.
diff --git a/modules/25-types/10-type-as-sets/en/data.yml b/modules/25-types/10-type-as-sets/en/data.yml
new file mode 100644
index 0000000..e882174
--- /dev/null
+++ b/modules/25-types/10-type-as-sets/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Types as sets
diff --git a/modules/25-types/20-union-types/en/EXERCISE.md b/modules/25-types/20-union-types/en/EXERCISE.md
new file mode 100644
index 0000000..d63a262
--- /dev/null
+++ b/modules/25-types/20-union-types/en/EXERCISE.md
@@ -0,0 +1,8 @@
+
+Implement the `lastIndex(str, char)` function that returns the index of the last occurrence of a character in the string or `null` if there is no such character.
+
+```typescript
+const str = 'test';
+lastIndex(str, 't'); // 3
+lastIndex(str, 'p'); // null
+```
diff --git a/modules/25-types/20-union-types/en/README.md b/modules/25-types/20-union-types/en/README.md
new file mode 100644
index 0000000..543faab
--- /dev/null
+++ b/modules/25-types/20-union-types/en/README.md
@@ -0,0 +1,36 @@
+
+In this lesson, we will learn how to work with type unions, which play a big role in TypeScript. They allow us to express a common situation in JavaScript where the return value or function argument can be of different types. For example, the `String.prototype.at()` method can return a value of type `string` or `undefined`.
+
+Concatenation is indicated by the `|` forward slash operator, with types on either side of it.
+
+Let's define our type for the function `at`:
+
+```typescript
+type at = (str: string, position: number) => string | undefined;
+```
+
+From the point of view of set theory, the union operation means union. When we combine several sets, we get a new set that includes all the elements of the original sets.
+
+In TypeScript, this means that we end up with a type that promises to contain a variable of one of the union types. This is how we can have a type that includes all the strings **OR** of a number:
+
+```typescript
+type NumberOrString = number | string;
+
+let val: NumberOrString = 10; // OK
+val = 'My string'; // OK
+val = true; // Type 'boolean' is not assignable to type 'NumberOrString'.
+```
+
+
+
+In practice, there are often cases where we need to support a function with many valid values. In JavaScript, we can connect a string not only with a string, but also with a number or with `true`. To solve a similar problem, we learned about function overloading in the past lessons. Let's describe the type of such a function using union:
+
+```typescript
+type AllowedToConcatenation = number | string | null | undefined | boolean;
+
+const concat = (base: AllowedToConcatenation, suffix: AllowedToConcatenation): string => `${base}${suffix}`;
+```
+
+To describe all allowed values of the `concat()` function through overloading, we would need to write code for each case separately. Here we have described the `AllowedToConcatenation` type through union once and applied it in two places.
+
+Union Types are used everywhere where a programmer wants to indicate that a variable can contain values of different but pre-described types. To specify arbitrary types, `unknown` or generics can be used, which we'll look at later in the course.
diff --git a/modules/25-types/20-union-types/en/data.yml b/modules/25-types/20-union-types/en/data.yml
new file mode 100644
index 0000000..36ac6be
--- /dev/null
+++ b/modules/25-types/20-union-types/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Union Types
diff --git a/modules/25-types/22-nullable/en/EXERCISE.md b/modules/25-types/22-nullable/en/EXERCISE.md
new file mode 100644
index 0000000..2604663
--- /dev/null
+++ b/modules/25-types/22-nullable/en/EXERCISE.md
@@ -0,0 +1,9 @@
+
+Реализуйте функцию `formatPrice()`, которая принимает число и возвращает строку с округлением до второго числа после запятой. Если пришел `null` или `undefined` должна вернуться `'$0.00'`.
+
+```typescript
+formatPrice(3.145); // '$3.15'
+formatPrice(200); // '$200.00'
+formatPrice(); // '$0.00'
+formatPrice(null); // '$0.00'
+```
diff --git a/modules/25-types/22-nullable/en/README.md b/modules/25-types/22-nullable/en/README.md
new file mode 100644
index 0000000..ca64e08
--- /dev/null
+++ b/modules/25-types/22-nullable/en/README.md
@@ -0,0 +1,51 @@
+
+В TypeScript `null` и `undefined` не просто значения. Это два типа, которые состоят из одного значения. Представим, если бы TypeScript работал так же, как JavaScript. Тогда эти значения можно было бы передавать в любом месте. И неважно, что там ожидается: строка, массив и тому подобное.
+
+Все было бы хорошо, пока не пришло время выполнения кода. В этот момент мы бы получили ошибку, потому что внутри функции ожидался бы массив, а пришел `null` или `undefined`. Такая проблема, например, существует в JavaScript:
+
+```javascript
+function foo(value) {
+ const upperValue = value.toUpperCase();
+ // остальная логика
+}
+
+foo(null); // Uncaught TypeError: Cannot read properties of null (reading 'toUpperCase')
+```
+
+В статически типизированных языках, где `null` используется как общий тип для всего, проверка типов ничего не подскажет. В таком случае возникает исключение `NullPointerException` — одно из самых запоминающихся для всех пользователей. Поэтому код начинает обрастать проверками на `null`:
+
+```java
+public void doSomething(SomeObject obj) {
+ if(obj != null) {
+ obj.myMethod();
+ }
+}
+
+doSomething(null);
+```
+
+Данный пример на Java показывает, что `null` может быть передан в любое место, где ожидается объект. Поэтому внутри функции мы должны проверить, что `obj` не равен `null`. Если бы мы не сделали этой проверки, то получили бы исключение `NullPointerException`.
+
+В TypeScript c правильной (`strict`) конфигурацией подобная проверка встроена, и статический анализатор скажет о возможной проблеме:
+
+```typescript
+function foo(value?: string | null) {
+ const upperValue = value.toUpperCase(); // Object is possibly 'null' or 'undefined'.
+ // остальная логика
+}
+```
+
+В данном случае мы получили ошибку компиляции, потому что `value` может быть `null` или `undefined`.
+
+Чтобы ее решить, нужно написать соответствующее условие или использовать оператор `?.`. Это позволяет избежать ошибок во время исполнения кода:
+
+```typescript
+function foo(value?: string | null) {
+ if (value !== null && value !== undefined) {
+ const upperValue = value.toUpperCase(); // (parameter) value: string
+ }
+ // остальная логика
+}
+```
+
+Это стало возможным благодаря выделению значений `null` и `undefined` в отдельные типы. Благодаря каждой проверке мы отсекаем не подходящее нам множество значений и получаем безопасный вызов метода. Такие проверки также называются отсечением типов (Differentiating Types) и Type Guards.
diff --git a/modules/25-types/22-nullable/en/data.yml b/modules/25-types/22-nullable/en/data.yml
new file mode 100644
index 0000000..b86f695
--- /dev/null
+++ b/modules/25-types/22-nullable/en/data.yml
@@ -0,0 +1,11 @@
+---
+name: Null и Undefined
+tips:
+ - >
+ [Type Guards и Differentiating
+ Types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types)
+ - |
+ [Type Guard](https://basarat.gitbook.io/typescript/type-system/typeguard)
+ - >
+ [Optional
+ chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining)
diff --git a/modules/25-types/25-literal-types/en/EXERCISE.md b/modules/25-types/25-literal-types/en/EXERCISE.md
new file mode 100644
index 0000000..577a922
--- /dev/null
+++ b/modules/25-types/25-literal-types/en/EXERCISE.md
@@ -0,0 +1,13 @@
+
+Implement the `makeTurn()` function that takes a `left` or `right` string and moves a turtle back and forth across a one-dimensional array of fixed size with five elements. If the turtle moves outside the array, an exception is thrown.
+
+```typescript
+const { makeTurn, state } = startGame();
+console.log(state); // ['turtle', null, null, null, null]
+
+makeTurn('left') // ERROR
+
+makeTurn('right');
+makeTurn('right');
+console.log(state); // [null, null, 'turtle', null, null]
+```
diff --git a/modules/25-types/25-literal-types/en/README.md b/modules/25-types/25-literal-types/en/README.md
new file mode 100644
index 0000000..f6cd87c
--- /dev/null
+++ b/modules/25-types/25-literal-types/en/README.md
@@ -0,0 +1,123 @@
+
+In programming there are situations when we work with a limited set of values of some type, for example, with certain strings. They may include reference data, statuses and so on. How the order status could look like:
+
+```
+Created
+Paid
+Shipped
+Delivered
+```
+
+The code that handles this data will save it to the database, send and receive it over the network, and check the status of the order.
+
+If we always use only generic types for such data, such as `string`, we will lose many advantages, e.g.:
+
+* The compiler will not see typos
+* The compiler will not see the use of invalid statuses
+* We won't be able to see what statuses we have.
+* The editor's autocomplete won't work
+
+To solve this problem, TypeScript supports literal types. They represent a set consisting of only one element. They are only available for the following types: `string`, `boolean`, `number`, and `BigInt`:
+
+```typescript
+type Hexlet = 'hexlet';
+type One = 1;
+type False = false;
+type BigN = 100n;
+```
+
+From the point of view of set theory, such a type represents a set that consists of a single element. And for a type system it is a restriction - nothing but the specified value can be assigned to a variable:
+
+```typescript
+type TestValue = 'test';
+let test: TestValue = 'test';
+
+test = 'string'; // Error: Type '"string"' is not assignable to type '"test"'.
+```
+
+## Combining literal types
+
+Using type union, we can get a type that takes only the values we need:
+
+```typescript
+type OrderStatus = 'Created' | 'Paid' | 'Shipped' | 'Delivered';
+```
+
+Literal types can be also combined with any other types. In this way we can get the restriction that all numbers and `false` fall under:
+
+```typescript
+type NumberFalse = number | false;
+```
+
+## String enums
+
+The problem described in this tutorial is implemented in most languages through enumerations, which are also added to TypeScript:
+
+```typescript
+enum OrderStatus {
+ Created = 'Created',
+ Paid = 'Paid',
+ Shipped = 'Shipped',
+ Delivered = 'Delivered',
+}
+```
+
+But TypeScript is not so good with enumerations.
+
+TypeScript is an add-on to JavaScript that adds types, but does not change the language itself.
+
+This is not the case with Enum. Enums are a language construct that remains to exist in the code after the code is translated into JavaScript.
+
+For this reason, some developers use Union Types instead, which allow you to do pretty much the same thing with string literals.
+
+However, it is still recommended to use Enum in application code, as it provides additional guarantees of reliability. And use Union Types in library code, as it is more flexible and provides additional possibilities.
+
+## Literal objects
+
+When configuring libraries, we encounter cases where we are expected to have one of the strings. For example, we are given a choice of several databases:
+
+```typescript
+const dataSourceConfig = {
+ type: 'postgre', // can be also mysql
+ host: 'localhost',
+ port: 5432,
+};
+
+const AppDataSource = new DataSource(dataSourceConfig)
+```
+
+The object literal type is used to describe such objects, where the fields are initialized with a single literal type or their intersection:
+
+```typescript
+type DataSourceOption = {
+ type: 'postgre' | 'mysql';
+ host: string;
+ port: number;
+}
+```
+
+With this type, we can ensure that the passed object contains only one of the two values in the `type` field, which acts as both documentation and constraint.
+
+This gives library authors an additional documentation tool and developers an autocomplete, and keeps them from making mistakes in the arguments passed.
+
+## Convert to literal type
+
+In the case of configuration objects, we often don't want them to be changed externally and expect specific values internally. This is where type conversion to literal via Type Assertion `as const` comes in handy:
+
+```typescript
+const ormConfig = {
+ type: 'mysql',
+ host: 'localhost',
+ port: 5432,
+} as const;
+```
+
+On the output we get a type with immutable (`readonly`) fields and literal types in the value. This technique also applies to arrays. It turns them into tuples - fixed-length arrays, also protected from change. And it also applies to simple types, such as `string`:
+
+```typescript
+const str = 'test' as const;
+
+type Str = typeof str; // 'test'
+```
+
+In this way, we can create types that will contain only certain values. This allows us to get additional guarantees from the compiler and simplify code handling.
diff --git a/modules/25-types/25-literal-types/en/data.yml b/modules/25-types/25-literal-types/en/data.yml
new file mode 100644
index 0000000..e344ab7
--- /dev/null
+++ b/modules/25-types/25-literal-types/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Literal Types
+tips:
+ - >
+ [Literal
+ Types](https://basarat.gitbook.io/typescript/type-system/literal-types)
diff --git a/modules/25-types/25-literal-types/ru/README.md b/modules/25-types/25-literal-types/ru/README.md
index 38e47e5..9f31ff1 100644
--- a/modules/25-types/25-literal-types/ru/README.md
+++ b/modules/25-types/25-literal-types/ru/README.md
@@ -1,5 +1,5 @@
-В программировании встречаются ситуации, когда мы работаем с ограниченным набором значений какого-то типа, например, c определенными строками. В них могут входить справочные данные, статусы и так далее. Как мог бы выглядеть статус заказа:
+В программировании встречаются ситуации, когда мы работаем с ограниченным набором значений какого-то типа, например, с определенными строками. В них могут входить справочные данные, статусы и так далее. Как мог бы выглядеть статус заказа:
```
Created
diff --git a/modules/25-types/30-intersection-types/en/EXERCISE.md b/modules/25-types/30-intersection-types/en/EXERCISE.md
new file mode 100644
index 0000000..7242617
--- /dev/null
+++ b/modules/25-types/30-intersection-types/en/EXERCISE.md
@@ -0,0 +1,6 @@
+Implement `Admin` type, which is the intersection of `AdminPermission` and `User` types. Implement the `addAdmin()` function that takes a value with the `User` type and returns a value with the `Admin` type. The value for the `permission` property should be `Permission.READ`.
+
+```typescript
+const user: User = { login: 'login1' };
+const admin = addAdmin(user); // { login: 'login1', permission: Permission.READ }
+```
diff --git a/modules/25-types/30-intersection-types/en/README.md b/modules/25-types/30-intersection-types/en/README.md
new file mode 100644
index 0000000..f624a00
--- /dev/null
+++ b/modules/25-types/30-intersection-types/en/README.md
@@ -0,0 +1,29 @@
+
+Along with union, an important operation in set theory is intersection. For developers who are used to the dynamics of JavaScript, this operation may seem less important. But you can't do without it, for example, when describing the merge type of objects.
+
+The intersection is indicated with the `&` symbol, on both sides of which the types are located.
+
+Let's define the type of the object with the order status, and then a stricter type with the exact price:
+
+```typescript
+type Order = {
+ status: 'Created',
+}
+
+type OneHundredOrder = Order & {
+ cost: 100
+}
+
+const myOrder: OneHundredOrder = {
+ status: 'Created',
+ cost: 100
+}
+```
+
+From the intersection of object types with the fields `status` **And** `cost` we get the type `OneHundredOrder`, which contains both of these fields.
+
+A type is a set of values. When we define an intersection of types, we get a new type that contains values that fit the constraints of both types.
+
+
+
+If we declare a variable `const StringAndNumber: string & number`, we need to assign to it a value that simultaneously belongs to the sets `string` and `number`. That is, it is both a string and a number. Such a value does not exist, so `StringAndNumber` will be of type `never`. `never` corresponds to an empty set - a type that does not have any value.
diff --git a/modules/25-types/30-intersection-types/en/data.yml b/modules/25-types/30-intersection-types/en/data.yml
new file mode 100644
index 0000000..ed119f3
--- /dev/null
+++ b/modules/25-types/30-intersection-types/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Intersections Types
diff --git a/modules/25-types/40-assignability/en/EXERCISE.md b/modules/25-types/40-assignability/en/EXERCISE.md
new file mode 100644
index 0000000..70977d0
--- /dev/null
+++ b/modules/25-types/40-assignability/en/EXERCISE.md
@@ -0,0 +1,6 @@
+Implement an object of the described `Form` type. The `name.value` field should be validated, but the `age` field should not.
+
+```typescript
+console.log(form.name.validator(form.name.value)); // true
+console.log(form.age.validator(form.age.value)); // false
+```
diff --git a/modules/25-types/40-assignability/en/README.md b/modules/25-types/40-assignability/en/README.md
new file mode 100644
index 0000000..f2ca845
--- /dev/null
+++ b/modules/25-types/40-assignability/en/README.md
@@ -0,0 +1,27 @@
+
+In this lesson, we will look at assigning one value to another. This is one of the basic variable operations in most languages. The most common error you will encounter in TypeScript is `Error: Type X is not assignable to type Y.`. This kind of code fails to compile, so you need to figure out how to fix it.
+
+Assigning one value to another and passing it as an argument to a function is called **assignability**:
+
+```typescript
+let x: number;
+const y: number = 10;
+x = y;
+
+function len(str: string): number {
+ return str.length;
+}
+len(false); // Error!
+```
+
+When assigning `x = y;` and passing the argument `f(false);`, one first checks whether the variable can contain the type being passed - whether the type `x` is compatible with the type `y`.
+
+If we think of types as sets of values, assignability is a check that the set of values of `x` is included in the set of values of `y`. For example, the literal type `‘one’` is included in the set of values of `string`, but the set of values of `number` is not.
+
+A variable of type `x` is assigned to a variable of type `y` if the set of values of `x` is included in the set of values of `y`. Or in other words - if the set of `x` values is a subset of the set of `y` values.
+
+So the next time you encounter the error `Type X is not assignable to type Y.`, don't immediately reduce everything to the most general type through `as any`. After all, in this case you completely disable type checking for this variable.
+
+You should first understand what is expected as input and what the function returns. And only after that you can modify your own types: expand the allowable types, for example, with the help of a union and only in extreme cases use the `any` hack.
+
+To understand what can be assigned to what in TypeScript, you need to look at the code from the point of view of type hierarchy and structural typing. This is the focus of the next lessons in this course.
diff --git a/modules/25-types/40-assignability/en/data.yml b/modules/25-types/40-assignability/en/data.yml
new file mode 100644
index 0000000..6f7a1d1
--- /dev/null
+++ b/modules/25-types/40-assignability/en/data.yml
@@ -0,0 +1,13 @@
+---
+name: Assignability
+tips:
+ - >
+ [Assignability in the old documentation](https://github.com/microsoft/TypeScript-New-Handbook/blob/master/reference/Assignability.md)
+ - >
+ [Assignability table in the official documentation](https://www.typescriptlang.org/docs/handbook/type-compatibility.html#any-unknown-object-void-undefined-null-and-never-assignability)
+definitions:
+ - name: Types Compatibility
+ description: >
+ a set of rules on the basis of which, when analysing a data type,
+ a decision is made about the possibility of replacing one data type
+ with another in such a way that the replacement does not disrupt program execution.
diff --git a/modules/25-types/50-type-hierarcy/en/EXERCISE.md b/modules/25-types/50-type-hierarcy/en/EXERCISE.md
new file mode 100644
index 0000000..9d783ac
--- /dev/null
+++ b/modules/25-types/50-type-hierarcy/en/EXERCISE.md
@@ -0,0 +1,20 @@
+
+Implement a function `getUserFriends(userResponseJSON, userId)` that takes a JSON string and the `userId` of a user as input. The JSON contains an array of users `users` and with an array of friends `friends` as `[userId, userId]` pairs. The function returns the list of user's friends by the passed `userId`.
+
+If the user with the specified ID is not found, the function should return an empty array.
+
+```typescript
+const userJson = JSON.stringify({
+ users: [
+ { id: 1, name: 'John', age: 20 },
+ { id: 2, name: 'Mary', age: 21 },
+ ],
+ friends: [
+ [1, 2],
+ ],
+});
+
+getUserFriends(userJson, 1); // [{ id: 2, name: 'Mary', age: 21 }]
+getUserFriends(userJson, 2); // [{ id: 1, name: 'John', age: 20 }]
+getUserFriends(userJson, 3); // []
+```
diff --git a/modules/25-types/50-type-hierarcy/en/README.md b/modules/25-types/50-type-hierarcy/en/README.md
new file mode 100644
index 0000000..f99f4d1
--- /dev/null
+++ b/modules/25-types/50-type-hierarcy/en/README.md
@@ -0,0 +1,146 @@
+
+In this lesson, we'll break down the relationship between types that builds a hierarchy.
+
+## Types as subsets
+
+Let's look at an example of `Type X is not assignable to type Y` error in a function for sorting items. Suppose we have already written a function `sort`. And to describe only its types, let's use the `declare` keyword:
+
+```typescript
+type ComparatorCallback = (item1: number, item2: number, index: number) => -1 | 0 | 1
+declare function sort(arr: Array, callback: ComparatorCallback): Array
+
+const arr = [1, 2, 3];
+const comparator = (item1: number, item2: number) => Math.sign(item1 - item2);
+
+sort(arr, comparator) // Error: Type 'number' is not assignable to type '0 | 1 | -1'.
+```
+
+The type checker generated an error: the union of literal types `0 | 1 | -1` is not compatible with the type `number`. One might think that the type system is wrong, and we should use `any`. But if we think of literal numeric types as subsets of `number`, everything falls into place.
+
+With this example, we can again see the connection between types and set theory. A set `A` is a subset of `B` if any element that belongs to `A` also belongs to `B`. So, by using the union operation, we get the relations between types, which build up into a hierarchy of nested sets - a hierarchy of types.
+
+## Literal types
+
+Recall that literal types exist for four data types: `boolean`, `string`, `number`, `BigInt`. As a result, any literal type can be assigned to a variable of the corresponding type:
+
+```typescript
+let num: number = 1;
+const two: 2 = 2;
+const notTrue: false = false;
+
+num = two;
+num = notTrue; // Type 'boolean' is not assignable to type 'number'.
+```
+
+Here `2` is used as a literal type which represents a set of one element - a double.
+
+The analyzer successfully skipped assigning the literal type of number to `number`, but we could not assign the literal `boolean` type anymore. To solve this problem, we can use the union of `number | boolean` types. But if we are not sure what can be assigned, we would have to do the union with a potentially huge number of types.
+
+In this case, the `unknown` type comes to our rescue.
+
+## `unknown`
+
+The `unknown` type is a superset of all available types. It allows you to assign a value of an arbitrary type to a variable:
+
+```typescript
+let unknownValue: unknown = 1;
+
+unknownValue = 2; // OK
+unknownValue = false; // OK
+unknownValue = 'string'; // OK
+```
+
+It may seem that the `unknown` type works in the same way as `any`. However, there is a fundamental difference between them. The `any` type disables type checking and allows you to perform any operations with a value, for example, to access the properties of a variable. The `unknown` type prohibits this and requires a preliminary check of the variable's type or conversion to the necessary type. Let's look at it by example:
+
+```typescript
+let unknownValue: unknown;
+
+unknownValue = 'string';
+unknownValue.toUpperCase(); // Error: Property 'toUpperCase' does not exist on type 'unknown'.
+```
+
+Here we were able to assign a string to the `unknownValue` variable, but we cannot call the `toUpperCase()` method because the compiler does not know that the variable contains a string. In order to call the method, we must first check the type of the variable.
+
+Another important property is that when we combine any type with `unknown` we always get `unknown`:
+
+```typescript
+type UnionWithUnknown = unknown | number | boolean;
+````
+
+This behavior is explained by the fact that `unknown` is a superset of all types, so any union with it gives it itself. The exception here is `any`, which even in this case disables type checking and does not obey the model of types as sets.
+
+Next, let's consider the case when we want to prohibit assigning values to a variable.
+
+## `never`
+
+Sometimes in practice you need to be sure that no value is assigned to a variable. This can be implemented using the `never` type:
+
+```typescript
+let neverValue: never;
+const two: 2 = 2;
+
+neverValue = two; // Type 'number' is not assignable to type 'never'
+```
+
+In this case, we got an error because `never` is an empty set that does not contain any element. Therefore, no value can be assigned to the `neverValue` variable.
+
+## Type sets
+
+From our current knowledge, we can draw the following picture of TypeScript's type sets:
+
+
+
+The `number` set also includes all unions of literal number types, and the `string` set includes all unions of literal strings:
+
+```typescript
+type NumberUnion = -2 | -1 | 1 | 2
+
+const one: NumberUnion = 1;
+const num: number = one;
+
+type StringUnion = 'a' | 'b' | 'c' | 'd'
+
+const aChar: StringUnion = 'a';
+const str: string = aChar;
+```
+
+Such a subset of types is called a subtype, and the set itself a supertype.
+
+The relationships between subtypes and supertypes are a key concept of any statically typed language. They form a hierarchy of types. This becomes especially important when we want to cast one type to another.
+
+## Type conversion
+
+Let's look at different variants of type conversion:
+
+```typescript
+let num = 1; // Implicit upward conversion
+let one: number = 1; // Explicit upward conversion
+
+let two = num as 2; // Explicit downward conversion
+
+let three = 3 as const; // Casting to a literal type - downward
+```
+
+When we assign a value to a variable or pass arguments to a function, TypeScript tries to do an upward conversion - from subtype to base type. It is also possible to explicitly set the upward cast. We have already used this feature to check whether it is possible to cast one type to another, or to specify explicitly which type of variable we expect.
+
+Casting a base type to a subtype is done explicitly with the `as` keyword. With this behavior, TypeScript accepts the type conversion as true. In some cases, this can lead to an error. Therefore, a downward type conversion is considered unsafe. You should take a close look at such code.
+
+Let's look at another example:
+
+```typescript
+const args = [8, 5]; // args: number[]
+const angle = Math.atan2(...args); // error! A spread argument must either have a tuple type or be passed to a rest parameter.
+console.log(angle);
+```
+
+Here, the compiler defines the `args` variable as the `number[]` type - an array with any number of numeric elements. The compiler has expanded the possible values in the array despite the fact that we have specified only two elements in the array. This is the implicit upward type conversion, where the compiler casts to a more general type.
+
+For this reason, an error occurs because the `Math.atan2()` method expects two arguments, and the type of the `args` variable can contain any number of elements. Let's fix this by using the `as` keyword:
+
+```typescript
+const args = [8, 5] as const; // readonly [8, 5]
+const angle = Math.atan2(...args); // okay
+console.log(angle);
+```
+
+Now the compiler defines the type for the `args` variable as the literal type `[8, 5]`. Although it is a set of type `number[]`, it is already a stricter type, which is an array of two concrete numbers, so there will be no error. Such a conversion is called a ‘top-down’ conversion, because we cast from a broader type to a narrower type containing fewer possible values.
diff --git a/modules/25-types/50-type-hierarcy/en/data.yml b/modules/25-types/50-type-hierarcy/en/data.yml
new file mode 100644
index 0000000..ed4a4a5
--- /dev/null
+++ b/modules/25-types/50-type-hierarcy/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Type hierarchy
+tips:
+ - >
+ [Type
+ Assertion](https://basarat.gitbook.io/typescript/type-system/type-assertion)
diff --git a/modules/25-types/50-type-hierarcy/ru/EXERCISE.md b/modules/25-types/50-type-hierarcy/ru/EXERCISE.md
index 0a1dec2..9dd7004 100644
--- a/modules/25-types/50-type-hierarcy/ru/EXERCISE.md
+++ b/modules/25-types/50-type-hierarcy/ru/EXERCISE.md
@@ -1,5 +1,5 @@
-Реализуйте функцию `getUserFriends(userResponseJSON, userId)`, которая принимает на вход JSON-строку и `userId` пользователя. JSON содержит массив пользователей `users` и с массив друзей `friends` в виде пар `[userId, userId]`. Функция возвращает список друзей пользователя по переданному `userId``.
+Реализуйте функцию `getUserFriends(userResponseJSON, userId)`, которая принимает на вход JSON-строку и `userId` пользователя. JSON содержит массив пользователей `users` и массив друзей `friends` в виде пар `[userId, userId]`. Функция возвращает список друзей пользователя по переданному `userId``.
Если пользователь с указанным id не найден, то функция должна вернуть пустой массив.
diff --git a/modules/25-types/50-type-hierarcy/ru/README.md b/modules/25-types/50-type-hierarcy/ru/README.md
index f6f5803..2080a84 100644
--- a/modules/25-types/50-type-hierarcy/ru/README.md
+++ b/modules/25-types/50-type-hierarcy/ru/README.md
@@ -32,7 +32,7 @@ num = two;
num = notTrue; // Type 'boolean' is not assignable to type 'number'.
```
-Здесь `2` используется как литеральный тип, который представляет из себя множество из одного элемента — двойки.
+Здесь `2` используется как литеральный тип, который представляет собой множество из одного элемента — двойки.
Анализатор успешно пропустил присваивание литерального типа числа к `number`, но литеральный `boolean` тип мы уже не смогли присвоить. Чтобы решить эту проблему, можно использовать объединение типов `number | boolean`. Но если мы не уверены, что может быть присвоено, нам пришлось бы делать объединение с потенциально огромным числом типов.
@@ -59,7 +59,7 @@ unknownValue = 'string';
unknownValue.toUpperCase(); // Error: Property 'toUpperCase' does not exist on type 'unknown'.
```
-Здесь мы смогли присвоить переменной `unknownValue` строку, но не можем вызвать метод `toUpperCase()`, потому что компилятор не знает, что в переменной находится строка. Для того, чтобы вызвать метод, нужно сначала проверить тип переменной.
+Здесь мы смогли присвоить переменной `unknownValue` строку, но не можем вызвать метод `toUpperCase()`, потому что компилятор не знает, что в переменной находится строка. Для того чтобы вызвать метод, нужно сначала проверить тип переменной.
Другим важным свойством является то, что при объединении любых типов с `unknown` мы всегда получаем `unknown`:
@@ -133,7 +133,7 @@ const angle = Math.atan2(...args); // error! A spread argument must either have
console.log(angle);
```
-Здесь компилятор определяет переменной `args` как тип `number[]` — массив с любым количеством числовых элементов. Компилятор расширил возможные значения в массиве, не смотря на то, что мы указали всего два элемента в массиве. Это и есть неявное восходящее приведение типа, когда компилятор приводит к более общему типу.
+Здесь компилятор определяет переменной `args` как тип `number[]` — массив с любым количеством числовых элементов. Компилятор расширил возможные значения в массиве, несмотря на то, что мы указали всего два элемента в массиве. Это и есть неявное восходящее приведение типа, когда компилятор приводит к более общему типу.
По этой причине возникает ошибка, потому что метод `Math.atan2()` ожидает два аргумента, а тип переменной `args` может содержать любое количество элементов. Исправим это с помощью ключевого слова `as`:
diff --git a/modules/25-types/60-structural-typing/en/EXERCISE.md b/modules/25-types/60-structural-typing/en/EXERCISE.md
new file mode 100644
index 0000000..6a9949a
--- /dev/null
+++ b/modules/25-types/60-structural-typing/en/EXERCISE.md
@@ -0,0 +1,13 @@
+
+Describe the `DataState` state type and the `LoadingStatus` enumeration. Then implement a `handleData()` function that takes `DataState` as input and returns a string depending on the state: `loading...` at `LoadingStatus.loading`, `error` at `LoadingStatus.error`, a string from the numeric field `data` at `LoadingStatus.success`. If the status is not included in the enumeration, the function returns `unknown`.
+
+```typescript
+const loading: DataState = { status: LoadingStatus.Loading };
+console.log(handleData(loading)); // loading...
+
+const error: DataState = { status: LoadingStatus.Error, error: new Error('error') };
+console.log(handleData(error)); // error
+
+const success: DataState = { status: LoadingStatus.Success, data: 42 };
+console.log(handleData(success)); // 42
+```
diff --git a/modules/25-types/60-structural-typing/en/README.md b/modules/25-types/60-structural-typing/en/README.md
new file mode 100644
index 0000000..ada3df9
--- /dev/null
+++ b/modules/25-types/60-structural-typing/en/README.md
@@ -0,0 +1,142 @@
+
+In JavaScript, it is possible to work with objects and classes in the same way. You don't need to rely on inheritance or interfaces. You only need the expected fields and methods. This approach is called duck typing. What walks like a duck and quacks like a duck is a duck:
+
+```javascript
+const user = {
+ firstName: 'Vasiliy',
+ lastName: 'Kuzenkov',
+ type: 'user'
+}
+
+const admin = {
+ firstName: 'Kirill',
+ lastName: 'Mokevnin',
+ type: 'admin'
+}
+
+const formatUser = (user) => [user.type, ':', user.firstName, user.lastName].join(' ');
+
+formatUser(user); // ok
+formatUser(admin); // ok
+```
+
+In languages like Java we would need to define an interface, then implement it separately for the `User` and `Admin` classes. And in the formatting method parameters the argument type would be this interface.
+
+Another option is to write an overloaded method for these two cases. Languages with this behavior use nominative typing - nominative typing.
+
+To organize the nominative typing approach in Java, you need to write a lot of extra code.
+
+To simplify the transition from JavaScript to TypeScript and to use checks before code execution, the structural typing approach was chosen. This is what we will be introduced to in this tutorial.
+
+With structural typing, we can easily rewrite our example in TypeScript:
+
+```typescript
+const user = {
+ firstName: 'Vassiliy',
+ lastName: 'Kuzenkov',
+ type: 'user'
+}
+
+const admin = {
+ firstName: 'Kirill',
+ lastName: 'Mokevnin',
+ type: 'admin'
+}
+
+type User = {
+ type: string,
+ firstName: string,
+ lastName: string
+}
+
+const formatUser = (user: User): string =>
+ [user.type, ':', user.firstName, user.lastName].join(' ');
+
+formatUser(user); // ok
+formatUser(admin); // ok
+```
+
+We have created the `User` type, which describes the expected structure of the object. In the `formatUser` function we specified that the expected argument must correspond to the `User` type. Thus, the `formatUser` function accepts only objects that contain all fields from the `User` object type.
+
+It is important to remember that structural typing does not protect us from the presence of additional fields in an object:
+
+```typescript
+const moderator = {
+ firstName: 'Danil',
+ lastName: 'Polovinkin',
+ type: 'moderator',
+ email: 'danil@polovinkin.com'
+}
+
+type User = {
+ type: string,
+ firstName: string,
+ lastName: string
+}
+
+const formatUser = (user: User): string =>
+ [user.type, ':', user.firstName, user.lastName].join(' ');
+
+formatUser(moderator); // ok
+```
+
+Even though we did not specify the `email` field in the `User` type, TypeScript will still not generate an error, because the `moderator` object has all the fields that are described in the `User` type.
+
+In structural typing, you can think of an object type as a description of a structure that imposes constraints on the values assigned. Or as a set of objects that can be assigned to a variable with this type.
+
+
+
+The fewer fields there are in an object type, the less specific constraints are placed on the assigned value. On sets, this means that an object type with additional fields will be a subset of an object type without these fields. If we talk about type contraction and expansion in object types, the extra fields narrow the type.
+
+Similarly to operations with sets for object types, we can form an understanding of intersection and union in structural typing.
+
+When merging `|` we expand the type - we increase the number of allowed values for the type. And when intersecting `&` - we narrow it. Thus, we reduce the number of allowed values:
+
+```typescript
+type IntersectionUser = {
+ username: string;
+ password: string;
+} & {
+ type: string;
+}
+
+const admin: IntersectionUser = { // a match with an object type is required both to the left and to the right of the & operator
+ username: 'test',
+ password: 'test',
+ type: 'admin'
+}
+
+type UnionUser = {
+ username: string;
+ password: string;
+} | {
+ type: string;
+}
+
+const user: UnionUser = { username: 'test', type: 'user' } // a match with one of the object types is sufficient
+```
+
+The resulting type `IntersectionUser` describes objects that contain the fields `username`, `password` and `type`. And `UnionUser` type describes objects that contain `username` and `password` **OR** `type` fields.
+
+
+
+In set algebra, the intersection of two sets is also called logical multiplication. For types, the term 'product type' is used. The union of sets is also called logical addition, and for types, the 'tagged union'.
+
+Try to answer what will happen if you use two object types with the same field name but different types in the intersection. This is a common mistake due to inattention or insufficient understanding of types as sets.
+
+
+ Answer
+When fields with the same names are encountered when intersecting object types, the resulting types of these fields will also be intersected, and the resulting type will be never.
+
+
+When using unified types in functions, the following point should be taken into account. Let's consider an example:
+
+```typescript
+const user: UnionUser = { username: 'test', type: 'user' };
+
+const func = (user: UnionUser) => {
+ console.log(user.type);
+};
+```
+
+The compiler will generate an error, because the type in the `user` variable can refer to either the left type or the right type. As a result, there is no guarantee that the `user` object will have any of the properties.
diff --git a/modules/25-types/60-structural-typing/en/data.yml b/modules/25-types/60-structural-typing/en/data.yml
new file mode 100644
index 0000000..fc06edb
--- /dev/null
+++ b/modules/25-types/60-structural-typing/en/data.yml
@@ -0,0 +1,18 @@
+---
+name: Structural typing
+tips:
+ - >
+ [Structural typing
+ in official documentation](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#structural-typing)
+ - >
+ [Nominal typing in TS](https://spin.atomicobject.com/2018/01/15/typescript-flexible-nominal-typing/)
+ - |
+ [Product Type](https://en.wikipedia.org/wiki/Product_type)
+ - |
+ [Tagged Union](https://en.wikipedia.org/wiki/Tagged_union)
+definitions:
+ - name: Structural typing
+ description: >
+ a principle that defines compatibility of types based on their description (structure).
+ A variable of type `A` may also be used where type `B` is expected,
+ if it has the same or broader structure.
diff --git a/modules/25-types/70-variability/en/EXERCISE.md b/modules/25-types/70-variability/en/EXERCISE.md
new file mode 100644
index 0000000..a042ad5
--- /dev/null
+++ b/modules/25-types/70-variability/en/EXERCISE.md
@@ -0,0 +1,17 @@
+
+Implement the function `applyTransactions(wallet)` and types `Transaction`, `Wallet`. `Wallet` contains a list of transactions as an array of elements of type `Transaction` and a numeric balance. `Transaction` contains an `apply` method that accepts a balance and returns a new balance.
+
+The `applyTransactions(wallet)` function must take an argument of type `Wallet` and return the balance after the entire transaction list has been applied. In case of an error in one of the transactions, it should return the original balance and not continue applying transactions.
+
+```typescript
+const wallet: Wallet = {
+ transactions: [
+ {
+ apply: (amount) => amount + 1,
+ },
+ ],
+ balance: 0
+}
+
+console.log(applyTransactions(wallet)) // 1
+```
diff --git a/modules/25-types/70-variability/en/README.md b/modules/25-types/70-variability/en/README.md
new file mode 100644
index 0000000..c2c9052
--- /dev/null
+++ b/modules/25-types/70-variability/en/README.md
@@ -0,0 +1,74 @@
+
+When we assign a value or pass arguments to a function call, TypeScript checks the types for compatibility. When we pass arguments to a function, the check is performed on both the parameter types and the return types.
+
+If we pass a function that returns a number as a callback to a sorting function that expects a return value of -1 | 0 | 1, we'll get an error: Type 'number' is not assignable to type '0 | 1 | -1':
+
+```typescript
+type ComparatorCallback = (item1: number, item2: number) => -1 | 0 | 1
+declare function sort(arr: Array, callback: ComparatorCallback): Array
+
+const arr = [1, 2, 3];
+const comparator = (item1: number, item2: number) => Math.sign(item1 - item2);
+// (item1: number, item2: number) => number;
+
+sort(arr, comparator); // Error: Type 'number' is not assignable to type '0 | 1 | -1'.
+```
+
+The set of values from the union of three literal types `-1 | 0 | 1` is a subset of `number`. But from the error we can understand that the returned type must be either the same or narrower. This type checking behavior is called **covariance**.
+
+To solve the problem with `ComparatorCallback`, we need to narrow the return type of the `comparator` function to `-1 | 0 | 1` or narrower. Let's rewrite the code without `Math.sign` to return the required type:
+
+```typescript
+type ComparatorCallback = (item1: number, item2: number) => -1 | 0 | 1
+declare function sort(arr: Array, callback: ComparatorCallback): Array
+
+const arr = [1, 2, 3];
+const comparator = (item1: number, item2: number) => {
+// (item1: number, item2: number) => -1 | 0 | 1;
+ if (item1 === item2) {
+ return 0;
+ }
+
+ return item1 > item2 ? 1 : -1;
+};
+
+sort(arr, comparator);
+```
+
+The code now passes type checking. The `comparator` return type has become narrower than the one required in `ComparatorCallback`.
+
+For function arguments, the type checking is done in reverse order. If we pass a function that expects literal type `1` instead of `number`, we get the error `Type 'number' is not assignable to type '1'.`:
+
+```typescript
+type ComparatorCallback = (item1: number, item2: number) => -1 | 0 | 1
+declare function sort(arr: Array, callback: ComparatorCallback): Array
+
+const arr = [1, 2, 3];
+const comparator = (item1: 1, item2: number) => Math.sign(item1 - item2) as -1 | 0 | 1;
+
+sort(arr, comparator); // Type 'number' is not assignable to type '1'.
+```
+
+The type `1` is a subset of `number`. And in our example, we pass a function that expects a narrower type on input to the `sort` function. You may also notice that we cast the return value type to `-1 | 0 | 1` using the `as` keyword. We needed a down conversion because the `Math.sign` typing returns `number`.
+
+When we pass arguments to a function, the expected types of the parameters should be broader than the actual types. This type checking behavior is called **contravariance**.
+
+Try to explain the behavior of type checking through variability yourself in the following example:
+
+```typescript
+type Formatter = (val: string) => string;
+
+const formatToConcrete: Formatter = (): 'test' => 'test';
+const formatToNumber: Formatter = (val: '1') => val; // Error!
+```
+
+
+ Answer
+ The parameter type can be wider and the output type can be narrower.
+ In the example, formatToConcrete takes no parameters. This gives a wider type than the required string. And it returns a narrower literal type. formatToNumber expects a narrower type on the input, that's why the error occurs.
+
+
+
+If you consider the legacy of JavaScript with utility typing when working with TypeScript, everything falls into place.
+
+To prevent the code from crashing with an error, it is enough to check for the presence of fields or methods of the required types. And to get guarantees in the outside world, you need the variable to fall under external constraints. For this purpose, the type must be narrower or the same.
diff --git a/modules/25-types/70-variability/en/data.yml b/modules/25-types/70-variability/en/data.yml
new file mode 100644
index 0000000..524c3c9
--- /dev/null
+++ b/modules/25-types/70-variability/en/data.yml
@@ -0,0 +1,15 @@
+---
+name: Covariance and contravariance
+tips:
+ - >
+ [Covariance and
+ contravariance](https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science))
+definitions:
+ - name: Covariance
+ description: >
+ type property when the types composing the union are
+ subsets of each other.
+ - name: Contravariance
+ description: >
+ type property, when the types composing a union are
+ supersets of each other.
diff --git a/modules/25-types/description.en.yml b/modules/25-types/description.en.yml
new file mode 100644
index 0000000..576ea14
--- /dev/null
+++ b/modules/25-types/description.en.yml
@@ -0,0 +1,4 @@
+---
+name: More about types
+description: |
+ Combining types using intersection and union, their peculiarities. In this module, we'll cover the basic concepts that allow you to gain a deeper understanding of how typing works in TypeScript and not be afraid of compiler errors.
diff --git a/modules/30-classes/10-class-fields/en/EXERCISE.md b/modules/30-classes/10-class-fields/en/EXERCISE.md
new file mode 100644
index 0000000..c981393
--- /dev/null
+++ b/modules/30-classes/10-class-fields/en/EXERCISE.md
@@ -0,0 +1,7 @@
+
+Implement the `CustomFile` class, which constructor is passed an object with the fields: `name` - the name of the file, and `size` - the size in bytes. Inside the class, define the `toString()` method, which should return a formatted string in the format ` ( bytes)`.
+
+```typescript
+const file = new CustomFile({ name: 'open-world.jpeg', size: 1000 });
+console.log(file.toString()); // open-world.jpeg (1000 bytes)
+```
diff --git a/modules/30-classes/10-class-fields/en/README.md b/modules/30-classes/10-class-fields/en/README.md
new file mode 100644
index 0000000..a7d4139
--- /dev/null
+++ b/modules/30-classes/10-class-fields/en/README.md
@@ -0,0 +1,73 @@
+
+Class typing in TypeScript adds a new syntax for defining classes that does not exist in JavaScript. This syntax exists only at the type checking level. It is cut or replaced in the resulting code. In this lesson, we'll explore the implementation of such classes.
+
+## Defining fields inside a class
+
+Let's start with an example. Look at this class:
+
+```typescript
+class Point {
+ x: number;
+ y: number;
+
+ constructor(x: number, y: number) {
+ this.x = x;
+ this.y = y;
+ }
+}
+
+const p = new Point(10, 20);
+console.log(p); // { x: 10, y: 20 }
+```
+
+Here we see a new syntax that describes the class fields: `x` and `y`. Their description is mandatory because classes are constructor functions, and functions are objects in TypeScript.
+
+Before moving on, let's understand the concept of a class field.
+
+## Class Field
+
+Usually in JavaScript, everything is referred to as properties. And the word ‘field’ is used as a synonym by those who come from other languages. But it's not the same thing.
+
+Inside a class, we define **fields** are the data of the class itself. And a **property** is what we use to interact with the object.
+
+Often properties and fields are the same, but this is not always the case. For example, a property can be read-only - a getter that takes information from a field. Or a property can be write-only - a setter that sets a new value for a field:
+
+```typescript
+class Point {
+ x: number;
+
+ y: number;
+
+ // The return type is not specified since this is a constructor
+ constructor(x: number, y: number) {
+ this.x = x;
+ this.y = y;
+ }
+
+ get inspect(): string {
+ return `(${this.x}, ${this.y})`
+ }
+}
+
+const p = new Point(2, 5);
+// There is a property, but there is no such field
+console.log(p.inspect); // (2, 5)
+```
+
+
+In the example, we defined a `inspect` getter that returns a string with the coordinates of a point. This property is read-only since we have not defined a setter.
+
+Fields can be initialized immediately when defining a class. This is convenient when the constructor is not needed or the data does not depend on its call - it is set statically inside:
+
+```typescript
+class Point {
+ x = 0;
+
+ y = 0;
+}
+
+const p = new Point();
+console.log(p); // { x: 0, y: 0 }
+```
+
+As in the case of ordinary variables, the type of fields is derived automatically during their initialization, so it is not necessary to specify an explicit type.
diff --git a/modules/30-classes/10-class-fields/en/data.yml b/modules/30-classes/10-class-fields/en/data.yml
new file mode 100644
index 0000000..d987d16
--- /dev/null
+++ b/modules/30-classes/10-class-fields/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Classes
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/2/classes.html)
diff --git a/modules/30-classes/15-class-as-types/en/EXERCISE.md b/modules/30-classes/15-class-as-types/en/EXERCISE.md
new file mode 100644
index 0000000..bb8ed15
--- /dev/null
+++ b/modules/30-classes/15-class-as-types/en/EXERCISE.md
@@ -0,0 +1,13 @@
+
+Implement the `CustomFile` class, which constructor is passed a file name and size in bytes or another file. Within the class, define an `toString()` method that should return a formatted string in the format `(copy) ( bytes)`. `(copy)` should only be output if the file is a copy of another file.
+
+```typescript
+const file = new CustomFile({ name: 'open-world.jpeg', size: 1000 });
+console.log(file.toString()); // open-world.jpeg (1000 bytes)
+
+const file2 = new CustomFile(file);
+console.log(file2.toString()); // (copy) open-world.jpeg (1000 bytes)
+
+const file3 = new CustomFile(file2);
+console.log(file2.toString()); // (copy) open-world.jpeg (1000 bytes)
+```
diff --git a/modules/30-classes/15-class-as-types/en/README.md b/modules/30-classes/15-class-as-types/en/README.md
new file mode 100644
index 0000000..078e4ed
--- /dev/null
+++ b/modules/30-classes/15-class-as-types/en/README.md
@@ -0,0 +1,53 @@
+
+Classes in TypeScript are both a value and a data type. The latter is especially important in the context of typing functions and methods, which we will explore in this lesson.
+
+Consider the following example:
+
+```typescript
+class Point {
+ x: number;
+
+ y: number;
+
+ constructor(x: number, y: number) {
+ this.x = x;
+
+ this.y = y;
+ }
+}
+
+function isEqual(p1: Point, p2: Point): boolean {
+ return p1.x === p2.x && p1.y === p2.y;
+}
+```
+
+Here, the `isEqual()` function accepts two arguments of `Point` type. Although we use the `Point` class as a type, we can pass any objects with `x` and `y` fields to the function:
+
+```typescript
+isEqual({ x: 1, y: 2 }, { x: 1, y: 2 }); // OK
+```
+
+This behavior is due to structural typing. When comparing types, TypeScript compares their structure, not their names. In practice, this makes it easier to work with external libraries and test stubs.
+
+TypeScript will explicitly require an instance of a class if it has private fields:
+
+```typescript
+class Point {
+ private x: number;
+
+ private y: number;
+
+ constructor(x: number, y: number) {
+ this.x = x;
+ this.y = y;
+ }
+
+ isEqual(p2: Point): boolean {
+ return this.x === p2.x && this.y === p2.y;
+ }
+}
+
+const point = new Point(1, 2);
+point.isEqual(new Point(10, 1)); // OK
+point.isEqual({ x: 1, y: 2}); // Error: Argument of type '{ x: number; y: number; }' is not assignable to parameter of type 'Point'.
+````
diff --git a/modules/30-classes/15-class-as-types/en/data.yml b/modules/30-classes/15-class-as-types/en/data.yml
new file mode 100644
index 0000000..c149025
--- /dev/null
+++ b/modules/30-classes/15-class-as-types/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Classes as types
+tips:
+ - >
+ [Constructor
+ overload](https://www.typescriptlang.org/docs/handbook/2/classes.html#constructors)
diff --git a/modules/30-classes/20-members-visibility/en/EXERCISE.md b/modules/30-classes/20-members-visibility/en/EXERCISE.md
new file mode 100644
index 0000000..067b11f
--- /dev/null
+++ b/modules/30-classes/20-members-visibility/en/EXERCISE.md
@@ -0,0 +1,14 @@
+
+Implement the `ImageCustomFile` class, which extends (`extends`) the `CustomFile` class with additional private fields: `width`, `height`. Also override the `toString()` method. Now it should additionally output `x`.
+
+```typescript
+const imageCustomFile = new ImageCustomFile({
+ name: 'image.png',
+ size: 100,
+ width: 200,
+ height: 300,
+});
+console.log(imageCustomFile.toString()); // image.png (100 bytes) 200x300
+```
+
+To call a method of a parent class, use `super.toString()`.
diff --git a/modules/30-classes/20-members-visibility/en/README.md b/modules/30-classes/20-members-visibility/en/README.md
new file mode 100644
index 0000000..09d0fa8
--- /dev/null
+++ b/modules/30-classes/20-members-visibility/en/README.md
@@ -0,0 +1,81 @@
+
+In some cases, properties and methods in a class are created for internal use only. Developers don't want to allow them to be called externally, otherwise they might accidentally start being used in ways that were not intended.
+
+In languages with classes, it is common to divide properties into public, private, and protected. The first ones are available to everyone, the second ones can be used only inside the class, and the third ones can be used inside the class and in its descendants. In this tutorial, we'll look at each of these types.
+
+## Public properties
+
+By default, in TypeScript, all properties are public. This can be marked explicitly with the `public` keyword:
+
+```typescript
+class Point {
+ public x: number;
+
+ public y: number;
+
+ constructor(x: number, y: number) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public someMethod() {
+ // some logic
+ }
+}
+```
+
+## Private properties
+
+You can also make properties private. Then it will no longer be possible to access them directly from the outside:
+
+```typescript
+class Point {
+ private x: number;
+
+ private y: number;
+
+ constructor(x: number, y: number) {
+ this.x = x;
+ this.y = y;
+ }
+}
+
+const p = new Point(10, 8);
+p.x; // Property 'x' is private and only accessible within class 'Point'.
+p.y; // Property 'y' is private and only accessible within class 'Point'.
+```
+
+## Protected properties
+
+Finally, properties can be made protected. This means that they are available inside the class and its descendants:
+
+```typescript
+class Point {
+ protected x: number;
+
+ protected y: number;
+
+ constructor(x: number, y: number) {
+ this.x = x;
+ this.y = y;
+ }
+}
+
+class Point3D extends Point {
+ protected z: number;
+
+ constructor(x: number, y: number, z: number) {
+ super(x, y);
+ this.z = z;
+ }
+
+ public getCoordinates() {
+ return [this.x, this.y, this.z]; // OK
+ }
+}
+
+const p = new Point3D(10, 8, 5);
+p.x; // Property 'x' is protected and only accessible within class 'Point' and its subclasses.
+p.y; // Property 'y' is protected and only accessible within class 'Point' and its subclasses.
+p.z; // Property 'z' is protected and only accessible within class 'Point3D' and its subclasses.
+```
diff --git a/modules/30-classes/20-members-visibility/en/data.yml b/modules/30-classes/20-members-visibility/en/data.yml
new file mode 100644
index 0000000..33aba0e
--- /dev/null
+++ b/modules/30-classes/20-members-visibility/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Protecting properties and methods
diff --git a/modules/30-classes/23-parameter-properties/en/EXERCISE.md b/modules/30-classes/23-parameter-properties/en/EXERCISE.md
new file mode 100644
index 0000000..c429b8e
--- /dev/null
+++ b/modules/30-classes/23-parameter-properties/en/EXERCISE.md
@@ -0,0 +1,7 @@
+
+Implement the `CustomFile` class, which constructor is passed a file name and size in bytes. Inside the class, define the `toString()` method, which should return a formatted string in the format ` ( bytes)`. Use the parameter properties to populate the class properties.
+
+```typescript
+const file = new CustomFile('open-world.jpeg', 1000);
+console.log(file); // open-world.jpeg (1000 bytes)
+```
diff --git a/modules/30-classes/23-parameter-properties/en/README.md b/modules/30-classes/23-parameter-properties/en/README.md
new file mode 100644
index 0000000..7fdf193
--- /dev/null
+++ b/modules/30-classes/23-parameter-properties/en/README.md
@@ -0,0 +1,33 @@
+
+Filling properties from constructor parameters is a common task when working with classes. That's why TypeScript has added a special syntax that allows you to do this automatically:
+
+```typescript
+class SomeClass {
+ constructor(public one: number, private two: string) {}
+
+ get three(): string {
+ return `${this.one} ${this.two}`;
+ }
+}
+```
+
+This code does the same thing as this code:
+
+```typescript
+ class SomeClass {
+ public one: number;
+
+ private two: string;
+
+ constructor(one: number, two: string) {
+ this.one = one;
+ this.two = two;
+ }
+
+ get three(): string {
+ return `${this.one} ${this.two}`;
+ }
+ }
+```
+
+The new syntax makes it possible not to duplicate the code for filling properties from parameters and makes it more concise. If there is some logic in the constructor, the properties still need to be filled in manually.
diff --git a/modules/30-classes/23-parameter-properties/en/data.yml b/modules/30-classes/23-parameter-properties/en/data.yml
new file mode 100644
index 0000000..0b8089e
--- /dev/null
+++ b/modules/30-classes/23-parameter-properties/en/data.yml
@@ -0,0 +1,9 @@
+---
+name: Parameter properties
+tips:
+ - >
+ [Constructor
+ overload](https://www.typescriptlang.org/docs/handbook/2/classes.html#constructors)
+ - >
+ [Typescript Constructor
+ Shorthand](https://dev.to/satansdeer/typescript-constructor-shorthand-3ibd)
diff --git a/modules/30-classes/30-class-extending/en/EXERCISE.md b/modules/30-classes/30-class-extending/en/EXERCISE.md
new file mode 100644
index 0000000..16df773
--- /dev/null
+++ b/modules/30-classes/30-class-extending/en/EXERCISE.md
@@ -0,0 +1,10 @@
+
+Implement the `HttpError` class, which must inherit from the built-in `Error` class and accept the error code as the first parameter and `message` as the second. Also implement classes `NotFoundError`, `UnauthorisedError`, `ForbiddenError`. Each of them should inherit from the `HttpError` class and have the `status` property, which is equal to the error code and `message` - the message passed to the base class. The error codes are: `404`, `401`, `403`.
+
+```typescript
+import { NotFoundError } from './errors';
+
+const error = new NotFoundError('Not Found');
+console.log(error.status); // 404
+console.log(error.message); // Not Found
+```
diff --git a/modules/30-classes/30-class-extending/en/README.md b/modules/30-classes/30-class-extending/en/README.md
new file mode 100644
index 0000000..335e63a
--- /dev/null
+++ b/modules/30-classes/30-class-extending/en/README.md
@@ -0,0 +1,71 @@
+
+In this lesson, we will look at inheritance. This is a mechanism that allows you to create subclasses based on existing classes. Subclasses inherit the properties and methods of the parent class and can extend them.
+
+In TypeScript, inheritance is implemented using the `extends` keyword:
+
+```typescript
+// TypeScript already includes a File class, so let's define our own file class named CustomFile
+class CustomFile {
+ constructor(public name: string, public size: number) {}
+}
+
+class ImageCustomFile extends CustomFile {
+ constructor(name: string, size: number, public width: number, public height: number) {
+ super(name, size);
+ }
+}
+```
+
+You can only inherit from one class. But the chain of inheritance can be infinite. For example, the `ImageCustomFile` class inherits from the `CustomFile` class, which can inherit from another class and so on.
+
+The whole chain of inheritance forms a class hierarchy. Since classes can also be used as types, the class hierarchy is completely the same as the type hierarchy. A subclass is a subtype of the base class and can be used instead of it, while specifying stricter restrictions.
+
+```typescript
+const file = new CustomFile('open-world.jpeg', 1000);
+const image = new ImageCustomFile('open-world.jpeg', 1000, 100, 100);
+
+const showImage = (image: ImageCustomFile) => {
+...
+};
+showImage(file); // Error
+```
+
+When inheriting, you can override methods of the parent class. In doing so, you must either preserve the method's signature or follow certain rules:
+
+- The parameter types of the overridden method are bivariant
+- The return type of the overridden method is covariant
+
+The parent method accepts `string` and returns `string`. The overridden method must have a broader or narrower type, e.g. `string | null` or `“some string”`. The return must be of a narrower type, e.g., `“some string”`:
+
+```typescript
+class CustomFileFactory {
+ createCustomFile(name: string, size: number): CustomFile {
+ return new CustomFile(name, size);
+ }
+}
+
+class ImageCustomFileFactory1 extends CustomFileFactory {
+ createCustomFile(name: string, size: number): ImageCustomFile { // OK
+ return new ImageCustomFile(name, size, 100, 100);
+ }
+}
+
+class ImageCustomFileFactory2 extends CustomFileFactory {
+ createCustomFile(name: 'file', size: number): CustomFile { // OK
+ return new ImageCustomFile(name, size, 100, 100);
+ }
+}
+
+class ImageCustomFileFactory3 extends CustomFileFactory {
+ createCustomFile(name: number, size: number): CustomFile { // Error!
+ return new ImageCustomFile(name, size, 100, 100);
+ }
+}
+
+
+class ImageCustomFileFactory3 extends CustomFileFactory {
+ createCustomFile(name: string, size: number): {} { // Error!
+ return new ImageCustomFile(name, size, 100, 100);
+ }
+}
+```
diff --git a/modules/30-classes/30-class-extending/en/data.yml b/modules/30-classes/30-class-extending/en/data.yml
new file mode 100644
index 0000000..83fcef7
--- /dev/null
+++ b/modules/30-classes/30-class-extending/en/data.yml
@@ -0,0 +1,8 @@
+---
+name: Inheritance
+tips:
+ - >
+ [Class
+ inheritance](https://www.typescriptlang.org/docs/handbook/2/classes.html#extends-clauses)
+ - |
+ [Mixins](https://basarat.gitbook.io/typescript/type-system/mixins)
diff --git a/modules/30-classes/70-static-property/en/EXERCISE.md b/modules/30-classes/70-static-property/en/EXERCISE.md
new file mode 100644
index 0000000..b6986d5
--- /dev/null
+++ b/modules/30-classes/70-static-property/en/EXERCISE.md
@@ -0,0 +1,8 @@
+
+Another useful use of static properties and methods is to create factory methods. A factory method is a static method that returns a new instance of a class. Implement a `UserResponse` class with a `user: string` field and a factory method `fromArray` that takes an array and returns an array of instances of the `UserResponse` class:
+
+```typescript
+const response = UserResponse.fromArray(['user1', 'user2', 'user3']);
+console.log(response[0].user); // user1
+console.log(response[0] instanceof UserResponse); // true
+```
diff --git a/modules/30-classes/70-static-property/en/README.md b/modules/30-classes/70-static-property/en/README.md
new file mode 100644
index 0000000..bb078d5
--- /dev/null
+++ b/modules/30-classes/70-static-property/en/README.md
@@ -0,0 +1,53 @@
+
+Sometimes we need to set a property or method that is common to all instances of that class. For example, to determine if an object is an instance of a class. In such a case, when declaring a method, we can specify the `static` keyword, and it will be available through the class name:
+
+```typescript
+class CustomFile {
+ private static readonly maxCustomFileSize = 1000;
+
+ static isCustomFile(file: CustomFile): boolean {
+ return file instanceof CustomFile;
+ }
+
+ protected static isCustomFileTooBig(size: number): boolean {
+ return size > CustomFile.maxCustomFileSize;
+ }
+
+ constructor(private name: string, private size: number) {
+ if (CustomFile.isCustomFileTooBig(size)) {
+ throw new Error('CustomFile is too big');
+ }
+ }
+}
+
+CustomFile.isCustomFile(new CustomFile('open-world.jpeg', 1000)); // true
+```
+
+Static methods and properties can also be assigned the `public`, `protected` and `private` access modifiers and the `readonly` immutability modifier. This allows you to restrict the use of properties and methods to the current class or descendants only.
+
+Unlike JavaScript, in TypeScript static properties and methods cannot be overridden in subclasses:
+
+```typescript
+class CustomFile {
+ static maxCustomFileSize = 1000;
+
+ static isCustomFile(file: CustomFile): boolean {
+ return file instanceof CustomFile;
+ }
+}
+
+class ImageCustomFile extends CustomFile {
+ static maxCustomFileSize = 2000; // Error!
+
+ static isCustomFile(file: CustomFile): boolean { // Error!
+ return file instanceof ImageCustomFile;
+ }
+}
+```
+Such code cannot be compiled. The access to static properties and methods of the parent class remains:
+
+```typescript
+const file = new ImageCustomFile();
+console.log(ImageCustomFile.maxCustomFileSize); // 1000
+console.log(ImageCustomFile.isCustomFile(file)); // true
+```
diff --git a/modules/30-classes/70-static-property/en/data.yml b/modules/30-classes/70-static-property/en/data.yml
new file mode 100644
index 0000000..1941705
--- /dev/null
+++ b/modules/30-classes/70-static-property/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Static methods and properties
diff --git a/modules/30-classes/70-static-property/ru/README.md b/modules/30-classes/70-static-property/ru/README.md
index f473c34..ee1af72 100644
--- a/modules/30-classes/70-static-property/ru/README.md
+++ b/modules/30-classes/70-static-property/ru/README.md
@@ -27,7 +27,7 @@ CustomFile.isCustomFile(new CustomFile('open-world.jpeg', 1000)); // true
Статическим методам и свойствам также можно назначить модификаторы доступа `public`, `protected` и `private` и модификатор неизменяемости `readonly`. Это позволяет ограничить использование свойств и методов только текущим классом или наследниками.
-В отличии от JavaScript в TypeScript статические свойства и методы не могут быть переопределены в подклассах:
+В отличие от JavaScript в TypeScript статические свойства и методы не могут быть переопределены в подклассах:
```typescript
class CustomFile {
diff --git a/modules/30-classes/80-abstract-classes/en/EXERCISE.md b/modules/30-classes/80-abstract-classes/en/EXERCISE.md
new file mode 100644
index 0000000..7a48711
--- /dev/null
+++ b/modules/30-classes/80-abstract-classes/en/EXERCISE.md
@@ -0,0 +1,48 @@
+
+Create an abstract class `Clock`, which will contain common logic for clock classes with different time output formats: 12-hour and 24-hour.
+
+The common logic should store data: hours `hours`, minutes `minutes` and seconds `seconds`. Also included in the common logic is the `tick()` method, which increments the second by one each time it is called. If the second is incremented to a value of 60, the minute is incremented by 1 and the second is reset to 0. The same is true for minutes and hours: if the minutes value is incremented to 60, the current hour is incremented and the minutes are reset to 0. If the hour value is incremented to 24, the hour is reset to 0.
+
+The initial time value is set when the object is created. The first parameter passed to the constructor is the current hour, the second is the minutes, and the third is the seconds.
+
+The abstract class `Clock` must require its successors to implement the `render()` method.
+
+```typescript
+
+// 24-hour format
+class Clock24 extends Clock {
+ render(): string {
+ const currentHour = this.hours % 24;
+ const hours = currentHour.toString().padStart(2, '0');
+ const minutes = this.minutes.toString().padStart(2, '0');
+
+ return `${hours} : ${minutes}`;
+ }
+}
+
+const clock24 = new Clock24(23, 59, 59);
+console.log(clock24.render()); // => '23 : 59'
+clock24.tick();
+console.log(clock24.render()); // => '00 : 00'
+
+// 12-hour format
+class Clock12 extends Clock {
+ render(): string {
+ const timeType = this.hours >= 12 ? 'PM' : 'AM';
+
+ let currentHour = this.hours > 12 ? this.hours - 12 : this.hours;
+ if (timeType === 'AM' && this.hours === 0) {
+ currentHour = 12;
+ }
+
+ const hours = currentHour.toString().padStart(2, '0');
+ const minutes = this.minutes.toString().padStart(2, '0');
+ return `${hours} : ${minutes} ${timeType}`;
+ }
+}
+
+const clock12 = new Clock12(23, 59, 59);
+console.log(clock12.render()); // => '11 : 59 PM'
+clock12.tick();
+console.log(clock12.render()); // => '12 : 00 AM'
+```
diff --git a/modules/30-classes/80-abstract-classes/en/README.md b/modules/30-classes/80-abstract-classes/en/README.md
new file mode 100644
index 0000000..ecb2056
--- /dev/null
+++ b/modules/30-classes/80-abstract-classes/en/README.md
@@ -0,0 +1,39 @@
+
+When we need to define a common behavior for several classes, it is convenient to use abstract classes, which we will explore in this lesson.
+
+Although abstract classes cannot be created directly, they can be inherited. They can also specify explicitly which method should be implemented in the inheritors:
+
+```typescript
+abstract class CustomFile {
+ protected name: string;
+
+ protected size: number;
+
+ constructor(name: string, size: number) {
+ this.name = name;
+ this.size = size;
+ }
+
+ sizeInKb(): number {
+ return this.size / 1024;
+ }
+}
+
+class ImageCustomFile extends CustomFile {
+ constructor(name: string, size: number) {
+ super(name, size);
+ }
+}
+```
+
+To take the common part of code out of classes, abstract classes are actively used to build application architecture and frameworks. For example, React has a class `Component` which can be represented as an abstract class. We can't create it directly, but it requires inheritors to implement the `render` method. This allows us to create components that will be rendered on initialization:
+
+```typescript
+abstract class Component {
+ abstract render(): void;
+
+ constructor() {
+ this.render();
+ }
+}
+```
diff --git a/modules/30-classes/80-abstract-classes/en/data.yml b/modules/30-classes/80-abstract-classes/en/data.yml
new file mode 100644
index 0000000..2ecff56
--- /dev/null
+++ b/modules/30-classes/80-abstract-classes/en/data.yml
@@ -0,0 +1,12 @@
+---
+name: Abstract classes
+definitions:
+ - name: Abstract class
+ description: >
+ is a class that cannot be created directly.
+ It is intended for inheritance only.
+ To create an abstract class, the `abstract` keyword is used.
+tips:
+ - >
+ [When to use abstract classes
+ in TypeScript](https://khalilstemmler.com/blogs/typescript/abstract-class)
diff --git a/modules/30-classes/description.en.yml b/modules/30-classes/description.en.yml
new file mode 100644
index 0000000..bd12edd
--- /dev/null
+++ b/modules/30-classes/description.en.yml
@@ -0,0 +1,4 @@
+---
+name: Classes
+description: |
+ Classes are used to describe identical objects with state and behavior. Classes in TypeScript extend the standard ones in JavaScript and provide additional tools that are so popular with programmers in "classic" OOP languages.
diff --git a/modules/35-interfaces/10-interfaces-overview/en/EXERCISE.md b/modules/35-interfaces/10-interfaces-overview/en/EXERCISE.md
new file mode 100644
index 0000000..44fad62
--- /dev/null
+++ b/modules/35-interfaces/10-interfaces-overview/en/EXERCISE.md
@@ -0,0 +1,7 @@
+
+You are given the IVehicle interface. The task is to implement a Car class based on this interface, which will have a calcFuelNeeded method that accepts the distance in kilometers and returns the fuel consumption for the specified distance. The Car class should also have a constructor function that accepts and implements the properties specified in the interface.
+
+```typescript
+const porche = new Car(4, 'red', true, 20);
+console.log(porche.calcFuelNeeded(200)); // 40
+```
diff --git a/modules/35-interfaces/10-interfaces-overview/en/README.md b/modules/35-interfaces/10-interfaces-overview/en/README.md
new file mode 100644
index 0000000..f0b9b2e
--- /dev/null
+++ b/modules/35-interfaces/10-interfaces-overview/en/README.md
@@ -0,0 +1,75 @@
+
+In this lesson, we will talk about interfaces. We will learn what they are, why they are needed, and in what cases they should be used instead of types.
+
+## What is an interface
+
+**Interface** is a TypeScript language construct that is used to describe objects and functions.
+
+Consider the following example:
+
+```typescript
+interface IUser {
+ firstName: string;
+ pointsCount: number;
+}
+
+const user: IUser = {
+ firstName: 'Mark',
+ pointsCount: 100,
+};
+```
+
+In this fragment, we have created an interface and implemented the `user` object on its basis.
+
+The interface looks like a definition of an object type. Object types and interfaces are interchangeable in almost all situations. Let's compare it with the example above:
+
+```typescript
+type User = {
+ firstName: string;
+ pointsCount: number;
+}
+
+const user: User = {
+ firstName: 'Mark',
+ pointsCount: 100,
+};
+```
+
+Here we have implemented the same object, but on the basis of a type instead of an interface. There is almost no difference.
+
+The TypeScript documentation says that we can choose whether to use a type or an interface. The choice depends on the situation. The question then arises, why do we need interfaces when we already have types?
+
+## When to use interfaces
+
+Interfaces and types are similar in many ways. But there are differences on the basis of which we can choose what we should use in a particular case.
+
+The main feature of interfaces is related to classes. Classes that implement interfaces contain within them the properties and methods specified in the implemented interface:
+
+```typescript
+interface Countable {
+ count(): number;
+}
+
+class SchoolClass implements Countable {
+ // Some logic
+ count(): number {
+ // It is mandatory to create this method as it is specified in the interface
+ }
+}
+
+const sc = new SchoolClass();
+// Returns student cound
+sc.count();
+```
+
+In this example, we have implemented an interface-based class. Now in all functions where objects are used only to count the number of something inside them, you can specify `Countable` instead of `SchoolClass`:
+
+```typescript
+// Not function doSomething(obj: SchoolClass)
+function doSomething(obj: Countable) {
+ // Is invoked somewhere here
+ obj.count();
+}
+```
+
+This is how interfaces make the function more versatile. We can pass any objects corresponding to `Countable`, not just `SchoolClass`. In programming, this feature is called subtype polymorphism ([Subtyping](https://en.wikipedia.org/wiki/Subtyping)).
diff --git a/modules/35-interfaces/10-interfaces-overview/en/data.yml b/modules/35-interfaces/10-interfaces-overview/en/data.yml
new file mode 100644
index 0000000..e93bfc2
--- /dev/null
+++ b/modules/35-interfaces/10-interfaces-overview/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: About interfaces
+tips:
+ - >
+ [Interfaces vs
+ Types](https://ultimatecourses.com/blog/typescript-interfaces-vs-types)
diff --git a/modules/35-interfaces/20-interface-using/en/EXERCISE.md b/modules/35-interfaces/20-interface-using/en/EXERCISE.md
new file mode 100644
index 0000000..5f5dfef
--- /dev/null
+++ b/modules/35-interfaces/20-interface-using/en/EXERCISE.md
@@ -0,0 +1,10 @@
+
+You are given several interfaces. Based on them, create the ISuperman interface. ISuperMan must have a guessWho method that accepts and returns a string.
+
+Based on the ISuperMan interface, create a `superMan` object. The guessWho method should work as follows: if any value other than superman (in any case) comes as a string in the argument, it should return the guess ‘It's a ${value}?’, otherwise ‘It's a ${value}!’.
+
+```typescript
+console.log(superMan.guessWho('bird')); // "It's a bird?";
+console.log(superMan.guessWho('plane')); "It's a plane?";
+console.log(superMan.guessWho('superman')); "It's a superman!";
+```
diff --git a/modules/35-interfaces/20-interface-using/en/README.md b/modules/35-interfaces/20-interface-using/en/README.md
new file mode 100644
index 0000000..d7858d3
--- /dev/null
+++ b/modules/35-interfaces/20-interface-using/en/README.md
@@ -0,0 +1,123 @@
+
+In this lesson, we will look at the use of interfaces. In the previous lesson we told you that their work is similar to the work of types in TypeScript. But they have their own peculiarities, which we will touch upon today.
+
+## Extending an interface with additional fields
+
+If an interface needs to be extended with additional fields after it has been initialized, we can re-declare the interface with new properties. This method is called **merging declarations**:
+
+```typescript
+interface IUser {
+ rating: number;
+}
+
+interface IUser {
+ nickname: string;
+ birthdate: number;
+}
+
+const sergey: IUser = {
+ nickname: 'Sergey',
+ birthdate: 1990,
+ rating: 1102,
+}
+```
+
+Here we created the `IUser` interface and then extended it with new properties for demonstration purposes. After that we created `Sergey` object on its basis.
+
+Let's consider another way of working with an interface.
+
+## Extending an interface using another interface
+
+We can extend an interface by creating another interface that inherits from it:
+
+```typescript
+interface IStudent extends IUser {
+ group: number;
+}
+
+const sergey: IStudent = {
+ nickname: 'Sergey',
+ birthdate: 1990,
+ rating: 1102,
+ group: 2,
+}
+```
+
+In this example, we have created another one based on our previous interface `IUser` - `IStudent`, to which we have added the `group` property. So the interface `IStudent` has all the properties of `IUser` and all the properties we specified when extending it from `IUser`, i.e. additionally `group`.
+
+Now let's look at how to work with multiple interfaces.
+
+## Extending multiple interfaces
+
+More interfaces can extend several other interfaces at once:
+
+```typescript
+interface IUser {
+ nickname: string;
+ rating: number;
+}
+
+interface IEditor {
+ courses: [string];
+ canEdit: boolean;
+}
+
+interface IAuthor extends IUser, IEditor {
+ team: string;
+}
+
+const sergey: IAuthor = {
+ nickname: 'Sergey',
+ rating: 20,
+ courses: ['typescript'],
+ canEdit: true,
+ team: 'Hexlet College'
+}
+```
+
+In the example above, we created an instance based on the `IAuthor` interface, which was created by extending the `IUser` and `IEditor` interfaces. This instance took all the properties of these interfaces and the property we specified when we created the `IAuthor` interface itself.
+
+## Creating intersection types
+
+TypeScript also allows us to create intersection types from multiple interfaces using the `&` literal:
+
+```typescript
+interface IOneWay {
+ one: string;
+}
+
+interface IOrAnother {
+ another: string;
+}
+
+type OneWayOrAnother = IOneWay & IOrAnother;
+
+const example: OneWayOrAnother = {
+ one: 'A',
+ another: 'B',
+}
+```
+
+Here we have created the type `OneWayOrAnother` based on two interfaces using the `&` literal. This type includes all properties of the specified interfaces.
+
+There are no significant differences between creating cross-types and extending interfaces. Almost always these actions will be interchangeable, so it is more a matter of convenience. But there are exceptions where [interface extension behaves differently from cross-type creation](https://stackoverflow.com/questions/52681316/difference-between-extending-and-intersecting-interfaces-in-typescript).
+
+It may happen that we don't know in advance all the properties that our interface will contain. But we know their possible contents. In such a case, it is convenient to use a special index signature, which allows us to describe the types of possible values:
+
+```typescript
+interface IPhoneBook {
+ [index:string]: number;
+}
+
+const myNotePad: IPhoneBook = {
+ ivan: 55531311,
+ sergey: 55500110,
+ mom: 55522111,
+}
+```
+
+In the example above, we solved the issue of creating a phone book by using an index signature. This allowed us not to specify many properties with names, but only once to specify the key type and its value type.
+
+## Conclusions
+
+Interfaces are another powerful tool in TypeScript along with types. It allows us to describe our data in a flexible way. It also lends itself conveniently to being extended and combined with other types or interfaces.
diff --git a/modules/35-interfaces/20-interface-using/en/data.yml b/modules/35-interfaces/20-interface-using/en/data.yml
new file mode 100644
index 0000000..4985954
--- /dev/null
+++ b/modules/35-interfaces/20-interface-using/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Using interfaces
+tips:
+ - >
+ [Official
+ documentation](https://www.typescriptlang.org/docs/handbook/2/objects.html)
diff --git a/modules/35-interfaces/20-interface-using/ru/README.md b/modules/35-interfaces/20-interface-using/ru/README.md
index e92a1c5..514719f 100644
--- a/modules/35-interfaces/20-interface-using/ru/README.md
+++ b/modules/35-interfaces/20-interface-using/ru/README.md
@@ -79,7 +79,7 @@ const sergey: IAuthor = {
## Создание intersection types
-Также TypeScript позволяет нам создавать перекрестные типы (intersection types) из нескольких интерфейсов c помощью литерала `&`:
+Также TypeScript позволяет нам создавать перекрестные типы (intersection types) из нескольких интерфейсов с помощью литерала `&`:
```typescript
interface IOneWay {
diff --git a/modules/35-interfaces/30-interface-implementation/en/EXERCISE.md b/modules/35-interfaces/30-interface-implementation/en/EXERCISE.md
new file mode 100644
index 0000000..8bd1317
--- /dev/null
+++ b/modules/35-interfaces/30-interface-implementation/en/EXERCISE.md
@@ -0,0 +1,13 @@
+
+Using the provided `IPhonebook` interface and the `Entry` type, implement the `Phonebook` class, which represents a telephone directory with the following properties:
+
+- `entries` is a database, an object whose entries represent names as keys and phone numbers as values. The property must be immutable and read-only
+- `get` - method that returns a phone by name
+- `set` - method that writes the name and phone to the directory
+
+Examples:
+```typescript
+const myNote = new Phonebook();
+myNote.set('help', 911);
+myNote.get('help'); // 911
+```
diff --git a/modules/35-interfaces/30-interface-implementation/en/README.md b/modules/35-interfaces/30-interface-implementation/en/README.md
new file mode 100644
index 0000000..e75c608
--- /dev/null
+++ b/modules/35-interfaces/30-interface-implementation/en/README.md
@@ -0,0 +1,96 @@
+
+In TypeScript, classes can interact closely with interfaces. In this tutorial, we'll look at how to extend interfaces with classes and how to create classes based on interfaces.
+
+## Extending an interface with classes
+
+In the last lesson, we saw how interfaces can extend other interfaces and combine them. Similarly, interfaces can be extended by classes:
+
+```typescript
+interface IBeep {
+ sayBeep: () => string;
+}
+
+interface IBoop {
+ sayBoop: () => string;
+}
+
+class Robo implements IBeep, IBoop {
+ sayBeep = () => 'beep';
+
+ sayBoop = () => 'boop';
+}
+
+const R2D2 = new Robo();
+R2D2.sayBeep(); // 'beep'
+```
+
+Here we extended the two interfaces with a class that inherited all the methods of the given interfaces. We had to write the inherited methods manually.
+
+## Creating classes based on interfaces
+
+We can create classes based on interfaces in the same way we create interfaces based on interfaces. But there are some differences.
+
+If we create an interface or type and then transpilate TypeScript into JavaScript, there will be no sample of that interface left in the code. At the same time, when we create a class, its sample is always transpiled into JavaScript.
+
+It turns out that the option with interfaces is more lightweight, but still the choice should depend on the problem we are solving.
+
+Creating a class based on an interface does not lead to an exact implementation of that interface in the class. TypeScript simply checks if the properties and methods of our class satisfy the properties declared in the interface. We write the class itself manually.
+
+Let's look at an example:
+
+```typescript
+interface ICalculate {
+ sum: (num1: number, num2: number ) => number;
+}
+
+class Summator implements ICalculate {
+ sum(num1, num2) { return num1 + num2; }
+ // For parameters the following message will be displayed: Parameter 'num1'/'num2' implicitly has an 'any' type,
+ // because TypeScript only checks the class against the interface, but does not fully inherit from it.
+ multiply(num1: number, num2: number) { return num1 * num2; }
+ // We added a new method, but TypeScript doesn't complain
+}
+
+let calculator = new Summator();
+ // Our code will work as if it worked for arguments with type any,
+ // because parameter types, as well as everything else, were not inherited by the class when the interface was implemented
+calculator.sum(2,3) // 5
+```
+
+An error in the implementation of an interface by a class is possible only when we do not implement one of the properties specified in the interface. Or we implement it differently than specified in the interface:
+
+```typescript
+interface ICalculate {
+ sum: (num1: number, num2: number ) => number;
+}
+
+class Summator implements ICalculate {
+ sum (num1: string, num2: string) { return num1 + num2 };
+ // We changed the argument types to string, i.e. we implemented the interface incorrectly
+ // In this case TypeScript will notice our error and will not compile:
+ // Type '(num1: string, num2: string) => string' is not assignable to type '(num1: number, num2: number) => number'.
+}
+```
+
+For the same reason, if we write a class that implements an interface with optional properties, we need to write everything ourselves. Otherwise, these properties will not be included in our class:
+
+```typescript
+interface ICalculate {
+ sum: (num1: number, num2: number) => number;
+ multiply? : (num1: number, num2: number) => number;
+}
+
+class Summator implements ICalculate {
+ sum (num1: number, num2: number) { return num1 + num2; }
+}
+
+const calculator = new Summator();
+calculator.sum(2,3) // 5
+calculator.multiply(2,3) // Property 'multiply' does not exist on type 'Summator'.
+```
+
+In the example above, we specified only the `sum` method when implementing the interface with the `Summator` class. As a result, the code compiled successfully because the `multiply` method was specified as optional. At the same time, we cannot address this method in an instance of our class.
+
+## Conclusions
+
+Since there are several different tools in TypeScript for the same things, we can implement classes using abstract class extensions instead of interfaces. But the choice will depend on the task at hand. Abstract classes provide us with access modifiers and constructors, while interfaces are more lightweight and simple.
diff --git a/modules/35-interfaces/30-interface-implementation/en/data.yml b/modules/35-interfaces/30-interface-implementation/en/data.yml
new file mode 100644
index 0000000..6541ee2
--- /dev/null
+++ b/modules/35-interfaces/30-interface-implementation/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Implementing interfaces with classes
diff --git a/modules/35-interfaces/description.en.yml b/modules/35-interfaces/description.en.yml
new file mode 100644
index 0000000..e05eba6
--- /dev/null
+++ b/modules/35-interfaces/description.en.yml
@@ -0,0 +1,4 @@
+---
+name: Interfaces
+description: |
+ Interfaces in TypeScript allow you to describe object types differently in the syntax familiar to OOP languages and extend the semantics - adding useful new uses.
diff --git a/modules/40-generics/10-generics-overview/en/EXERCISE.md b/modules/40-generics/10-generics-overview/en/EXERCISE.md
new file mode 100644
index 0000000..bbc50bf
--- /dev/null
+++ b/modules/40-generics/10-generics-overview/en/EXERCISE.md
@@ -0,0 +1,8 @@
+
+Implement a generic `last()` that retrieves the last element from the array if there is one, or null if there is none:
+
+```typescript
+last([]); // null
+last([3, 2]); // 2
+last(['code-basics', 'hexlet']); // hexlet
+```
diff --git a/modules/40-generics/10-generics-overview/en/README.md b/modules/40-generics/10-generics-overview/en/README.md
new file mode 100644
index 0000000..33a4f03
--- /dev/null
+++ b/modules/40-generics/10-generics-overview/en/README.md
@@ -0,0 +1,105 @@
+
+Static typing protects the code from a large class of errors related to incorrect use of types. But everything has its own price. In some situations it is enough to add type descriptions, in some situations we have to introduce new and not always simple concepts, for example, generics. In this lesson, we will start to get acquainted with them.
+
+Let's introduce the function of merging two arrays. In JavaScript, this code is written quite simply:
+
+```javascript
+const merge = (coll1, coll2) => {
+ const result = [];
+ result.push(...coll1);
+ result.push(...coll2);
+ return result;
+};
+
+merge([1, 2], [3, 4]); // [1, 2, 3, 4]
+merge(['one', 'two'], ['three']); // ['one', 'two', 'three']
+```
+
+The convenience of dynamic typing here is that this function automatically works for any arrays, no matter what is stored in them.
+
+This trick will not work in statically typed languages. You will have to specify a specific type:
+
+```typescript
+function merge(coll1: number[], coll2: number[]): number[] {
+ const result = [];
+ result.push(...coll1);
+ result.push(...coll2);
+ return result;
+}
+
+merge([1, 2], [3, 4]); // [1, 2, 3, 4]
+```
+
+If you need to merge arrays consisting of strings, you will have to use function overloading. But inside there will be a problem with the returned type, which will be different depending on the input parameters:
+
+```typescript
+function merge(coll1: number[], coll2: number[]): number[];
+function merge(coll1: string[], coll2: string[]): string[];
+```
+
+In languages with true function overloading, the problem will be that there will be many functions that have the same body. That is, in essence, duplication of logic for all possible input types.
+
+This situation is so common and difficult that a whole subsystem in the type system has been created for it. It is called generics.
+
+**Generics** applied to functions is a mechanism that allows you to create such functions which have the same processing logic for different data types. Sometimes such functions are called generalized functions.
+
+Below is an example of implementing the `merge()` function in a generalized form:
+
+```typescript
+// or like this
+// function merge(coll1: T[], coll2: T[]): T[]
+function merge(coll1: Array, coll2: Array): Array {
+ // The body of the function did not change!
+ const result = [];
+ result.push(...coll1);
+ result.push(...coll2);
+ return result;
+}
+
+// Works with any array types
+// The arrays themselves must have a matching type
+merge([1, 2], [3, 4]); // [1, 2, 3, 4]
+merge(['one', 'two'], ['three']); // ['one', 'two', 'three']
+```
+
+Here we see a new syntax that we need to get used to. If we don't go into details, the `` entry after the function name indicates that we have a generic in front of us, which is parameterized by type T. T is a designation that we could have used any other capital letter, such as X.
+
+Most often we will see this designation as it is common practice.
+
+What exactly is underneath the type in terms of generic code is not important. It can be an object, a number, a string, or a boolean value. In the example calls above, it's a number for the first call and a string for the second call. You could also make calls with boolean values in the same way:
+
+```typescript
+merge([true], [false, false]); // [true, false, false]
+```
+
+Further inside the function we see that the logic of work is the same for all types and does not depend on the type. We just move array elements into another array. At this point, the code looks familiar.
+
+We still need to deal with the parameters and the return value.
+
+The `Array` record describes a generalized array - also a generic one, but for a type. In place of this parameter can be any array, for example, `number[]` or `boolean[]`. Accordingly, in the function code we say that we expect two arrays of the same type as input and the same type as output.
+
+The name of the parameter of type T has an important role here. If we used a different letter, it would have to be changed for all the parts inside:
+
+```typescript
+function merge(coll1: Array, coll2: Array): Array
+```
+
+This is how TypeScript understands that the types of the input arrays and the resulting array are the same. That is, you can't call this function by passing an array of numbers and strings at the same time.
+
+```typescript
+const result = merge([1, 2], ['wow']); // Error!
+```
+
+But the types may not be the same. Below is an example of a generic that returns the first element of any array and null if it is empty:
+
+```typescript
+function first(coll: Array): T | null {
+ return coll.length > 0 ? coll[0] : null;
+}
+
+first([]); // null
+first([3, 2]); // 3
+first(['code-basics', 'hexlet']); // code-basics
+```
+
+Generics is a big topic that will be covered in the next lessons. Now our task is to familiarize ourselves with the general concept and gradually start using it.
diff --git a/modules/40-generics/10-generics-overview/en/data.yml b/modules/40-generics/10-generics-overview/en/data.yml
new file mode 100644
index 0000000..4130b30
--- /dev/null
+++ b/modules/40-generics/10-generics-overview/en/data.yml
@@ -0,0 +1,13 @@
+---
+name: Introductions into generics
+definitions:
+ - name: Generic type
+ description: >
+ an abstract type that can be replaced by a concrete type.
+ When we write code, we can describe the behavior of generalized types
+ or their relationship with other generalized types without knowing
+ which type will be used in the place where they are used.
+tips:
+ - >
+ [Parametric
+ polymorphism](https://en.wikipedia.org/wiki/Parametric_polymorphism)
diff --git a/modules/40-generics/20-generic-types/en/EXERCISE.md b/modules/40-generics/20-generic-types/en/EXERCISE.md
new file mode 100644
index 0000000..9314841
--- /dev/null
+++ b/modules/40-generics/20-generic-types/en/EXERCISE.md
@@ -0,0 +1,14 @@
+
+Implement a description of the generalized type `MySet`, which is an analog of the JavaScript set `Set`. An example of using an object of this type:
+
+```typescript
+const s: MySet = ...;
+// Adding an item returns the number of items
+s.add(1); // 1
+s.add(10); // 2
+
+s.has(1); // true
+s.has(8); // false
+```
+
+The type includes two methods: `add()` and `has()`. The data inside must be stored in the `items` property.
\ No newline at end of file
diff --git a/modules/40-generics/20-generic-types/en/README.md b/modules/40-generics/20-generic-types/en/README.md
new file mode 100644
index 0000000..027d89d
--- /dev/null
+++ b/modules/40-generics/20-generic-types/en/README.md
@@ -0,0 +1,87 @@
+
+In this lesson we will talk more about Generic Types. Let's take an array as an example.
+
+An array is a container type that stores values of any specified type inside it. The logic of array operation does not depend on the type of data stored inside. This definition automatically indicates that we are dealing with a generalized type.
+
+To work with such a type, we need to instantiate the internal type at the moment when we want to start working with data of this type:
+
+```typescript
+const numbers: Array = [];
+numbers.push(1);
+
+const strings: Array = [];
+numbers.push('hexlet');
+```
+
+The type that is specified inside the angle brackets is called **type parameter**. This name was chosen for a reason - specifying a parameter looks like a function call. Below we will see that this way of looking at generics helps us to better understand how they work.
+
+Let's imagine that we want to define our own collection, which works like an array, but with additional features. Such collections are often made in ORMs to work with data loaded from a database. Let's first describe a specific version of this type that works only with numbers and a couple of standard methods:
+
+```typescript
+type MyColl = {
+ data: Array;
+ forEach(callback: (value: number, index: number, array: Array) => void): void;
+ at(index: number): number | undefined;
+}
+```
+
+Here we see that the collection data is stored in a numeric array. There are two methods defined in the type, one of which (`forEach`) passes the elements of the collection to the callback, and the other (`at`) returns the elements of the collection at the specified index. One possible implementation of this type might look like this:
+
+```typescript
+// The types can be omitted as they are specified in `MyColl`
+const coll: MyColl = {
+ data: [1, 3, 8],
+ forEach(callback) {
+ this.data.forEach(callback);
+ },
+ at(index) {
+ return this.data.at(index); // target >= ES2022
+ },
+}
+
+coll.at(-1); // 8
+```
+
+Now let's try to generalize this type, i.e. make it generic. To do this, we need to do one simple thing: for elements of the collection, instead of `number` write `T` (or any other name starting with a capital letter) and add `T` as a type parameter to the definition:
+
+```typescript
+type MyColl = {
+ data: Array;
+ forEach(callback: (value: T, index: number, array: Array) => void): void;
+ at(index: number): T | undefined;
+}
+```
+
+This type definition can be viewed as a kind of function definition. When a specific type is specified, for example, `MyColl`, then `T` in this situation is replaced by `string` inside the type definition. And if other generics are used inside the type, they "call" the type further. That is, it all works like nested function calls.
+
+## Limitations of generics
+
+Generics can have limitations. For example, we can say that the type that is passed to a generic must implement some interface. This is done using the `extends` keyword. Suppose we can make our `MyColl` type work only with types that implement the `HasId` interface:
+
+```typescript
+interface HasId {
+ id: number;
+}
+
+type MyColl = {
+ data: Array;
+ forEach(callback: (value: T, index: number, array: Array) => void): void;
+ at(index: number): T | undefined;
+}
+```
+
+This allows us to use the `MyColl` type only with types that implement the `HasId` interface. For example, such code will not work:
+
+```typescript
+const coll: MyColl = {
+ data: [1, 3, 8],
+ forEach(callback) {
+ this.data.forEach(callback);
+ },
+ at(index) {
+ return this.data.at(index); // target >= ES2022
+ },
+}
+```
+
+Generics themselves are found everywhere in the code of libraries and frameworks. For example, in `React` component types are wrapped in generics so that you can specify props types. Generics can be used to create more generic types that can work with different data types, which we will explore in the next lessons.
diff --git a/modules/40-generics/20-generic-types/en/data.yml b/modules/40-generics/20-generic-types/en/data.yml
new file mode 100644
index 0000000..bca1043
--- /dev/null
+++ b/modules/40-generics/20-generic-types/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Generics (Types)
+tips:
+ - >
+ [Generic
+ constraints](https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-constraints)
diff --git a/modules/40-generics/20-generic-types/ru/EXERCISE.md b/modules/40-generics/20-generic-types/ru/EXERCISE.md
index d4e7d70..47b21c0 100644
--- a/modules/40-generics/20-generic-types/ru/EXERCISE.md
+++ b/modules/40-generics/20-generic-types/ru/EXERCISE.md
@@ -1,5 +1,5 @@
-Реализуйте описание обобщенного типа `MySet`, который представляет из себя аналог множества `Set` из JavaScript. Пример использования объекта этого типа:
+Реализуйте описание обобщенного типа `MySet`, который представляет собой аналог множества `Set` из JavaScript. Пример использования объекта этого типа:
```typescript
const s: MySet = ...;
diff --git a/modules/40-generics/20-generic-types/ru/README.md b/modules/40-generics/20-generic-types/ru/README.md
index 78ca1a5..0fde30d 100644
--- a/modules/40-generics/20-generic-types/ru/README.md
+++ b/modules/40-generics/20-generic-types/ru/README.md
@@ -1,7 +1,7 @@
В этом уроке поговорим подробнее про Generic Types. Возьмем для примера массив.
-
+
Массив — это тип-контейнер, который хранит внутри себя значения любого указанного типа. Логика работы массива не зависит от типа данных, хранящихся внутри. Такое определение автоматически говорит о том, что мы имеем дело с обобщенным типом.
@@ -86,4 +86,4 @@ const coll: MyColl = {
}
```
-Сами дженерики встречаются повсеместно в коде библиотек и фреймворков. Например в `React` типы компонентов оборачиваются в дженерики, чтобы можно было указать типы пропсов. С помощью дженериков можно создавать более универсальные типы, которые могут работать с разными типами данных, что мы и рассмотрим в следующих уроках.
+Сами дженерики встречаются повсеместно в коде библиотек и фреймворков. Например, в `React` типы компонентов оборачиваются в дженерики, чтобы можно было указать типы пропсов. С помощью дженериков можно создавать более универсальные типы, которые могут работать с разными типами данных, что мы и рассмотрим в следующих уроках.
diff --git a/modules/40-generics/30-generic-functions/en/EXERCISE.md b/modules/40-generics/30-generic-functions/en/EXERCISE.md
new file mode 100644
index 0000000..c2a07bc
--- /dev/null
+++ b/modules/40-generics/30-generic-functions/en/EXERCISE.md
@@ -0,0 +1,14 @@
+
+Implement a description of a generic `MyArray` type that represents an analog of an array from JavaScript. Example of using an object of this type:
+
+```typescript
+const coll: MyArray = ...;
+coll.push(1); // 1
+coll.push(10); // 2
+coll.push(99); // 3
+
+const newColl = coll.filter((value) => value % 2 == 0);
+console.log(newColl.items); // [10]
+```
+
+The type includes two methods: [push()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) and [filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), matching the signature of Array methods. The data inside should be stored in the `items` property. For `push()`, accept the convention that the method takes only one parameter. Ignore the other parameters.
diff --git a/modules/40-generics/30-generic-functions/en/README.md b/modules/40-generics/30-generic-functions/en/README.md
new file mode 100644
index 0000000..17a8f09
--- /dev/null
+++ b/modules/40-generics/30-generic-functions/en/README.md
@@ -0,0 +1,59 @@
+
+Let's imagine that generics have disappeared from the language. Then code duplication will occur. We will have to describe the same algorithm for different data types many times.
+
+Let's take for example the `last()` function returning the last element of an array. Below is its generalized version:
+
+```typescript
+function last(coll: T[]): T {
+ return coll[coll.length - 1];
+}
+```
+
+Generics can also be used in arrow functions:
+
+```typescript
+const last = (coll: T[]): T => {
+ return coll[coll.length - 1];
+};
+```
+
+Now let's try to implement the same behavior, but without using generics. To do this, we will have to create one function for each type. And the name of the function must be unique:
+
+```typescript
+function lastForNumberType(coll: number[]): number {
+ return coll[coll.length - 1];
+}
+
+function lastForStringType(coll: string[]): string {
+ return coll[coll.length - 1];
+}
+
+// Here are definitions for all other types
+```
+
+If there are several types, the number of functions to be defined will be defined as the product of the number of all possible types by the number of type parameters.
+
+Implementing a generic using an overloaded function simplifies the task. Then you won't have to create new names:
+
+```typescript
+function last(coll: number[]): number;
+function last(coll: string[]): string;
+// Here are definitions for all other types
+
+function last(coll: any[]): any {
+ return coll[coll.length - 1];
+}
+```
+
+In the case of TypeScript, the logic will not even be duplicated, but this is a peculiarity of TypeScript. In other statically typed languages, the logic will have to be duplicated as well.
+
+Whichever implementation we choose, two things must be observed:
+
+* Values passed internally are not used in any way. They are only moved from one place to another
+* The logic always remains the same. There are no conditional constructs on data type
+
+In Computer Science, the property of a function that allows values of different types to be processed in one way (using one algorithm) is called parametric polymorphism. That is, generics are TypeScript's implementation of parametric polymorphism.
+
+Parametric polymorphism plays an important role in statically typed languages, where functions have to explicitly specify types. Almost all high-level statically typed languages have it. In Java and C# it is also called generics. C++ uses the name templates, but the meaning doesn't change, although templates in C++ are more than parametric polymorphism.
+
+In contrast to statically typed languages, generics are not needed in dynamically typed languages such as JavaScript, Python, Ruby, PHP. In such languages, any generalized algorithm automatically works for all data types.
diff --git a/modules/40-generics/30-generic-functions/en/data.yml b/modules/40-generics/30-generic-functions/en/data.yml
new file mode 100644
index 0000000..5ce08ec
--- /dev/null
+++ b/modules/40-generics/30-generic-functions/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Generics (Functions)
+tips:
+ - >
+ [TypeScript
+ Generic Functions](https://www.geeksforgeeks.org/typescript-generic-functions/)
diff --git a/modules/40-generics/30-generic-functions/ru/EXERCISE.md b/modules/40-generics/30-generic-functions/ru/EXERCISE.md
index 404cb16..5311124 100644
--- a/modules/40-generics/30-generic-functions/ru/EXERCISE.md
+++ b/modules/40-generics/30-generic-functions/ru/EXERCISE.md
@@ -1,5 +1,5 @@
-Реализуйте описание обощенного типа `MyArray`, который представляет аналог массива из JavaScript. Пример использования объекта этого типа:
+Реализуйте описание обобщенного типа `MyArray`, который представляет аналог массива из JavaScript. Пример использования объекта этого типа:
```typescript
const coll: MyArray = ...;
diff --git a/modules/40-generics/30-generic-functions/ru/README.md b/modules/40-generics/30-generic-functions/ru/README.md
index a295562..75bff48 100644
--- a/modules/40-generics/30-generic-functions/ru/README.md
+++ b/modules/40-generics/30-generic-functions/ru/README.md
@@ -55,7 +55,7 @@ function last(coll: any[]): any {
Какой бы вариант реализации мы не выбрали, соблюдаются две вещи:
-* Значения, передаваемые во внутрь, никак не используются. Они только перекладываются из одного места в другое
+* Значения, передаваемые внутрь, никак не используются. Они только перекладываются из одного места в другое
* Логика работы всегда остается одной и той же. Условные конструкции по типу данных отсутствуют
В Computer Science свойство функции, позволяющее обрабатывать значения разных типов одним способом (используя один алгоритм), называется параметрическим полиморфизмом. То есть дженерики — это реализация параметрического полиморфизма в TypeScript.
diff --git a/modules/40-generics/40-many-parameters/en/EXERCISE.md b/modules/40-generics/40-many-parameters/en/EXERCISE.md
new file mode 100644
index 0000000..3918fea
--- /dev/null
+++ b/modules/40-generics/40-many-parameters/en/EXERCISE.md
@@ -0,0 +1,13 @@
+
+Implement a description of the generalized type `MyMap`, which is an analog of the associative array from JavaScript. Example of using an object of this type:
+
+```typescript
+const map: MyMap = ...;
+map.set('one', 1);
+map.set('two', 2);
+
+map.get('one'); // 1
+map.get('two'); // 2
+```
+
+The type includes two methods `set()` and `get()`. The first method accepts two generic parameters: a key and a value. The second method accepts the key and returns the value. Values are stored inside the object as a JavaScript built-in class [Map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map).
diff --git a/modules/40-generics/40-many-parameters/en/README.md b/modules/40-generics/40-many-parameters/en/README.md
new file mode 100644
index 0000000..6406a89
--- /dev/null
+++ b/modules/40-generics/40-many-parameters/en/README.md
@@ -0,0 +1,40 @@
+
+Generics, like ordinary functions, can have several type parameters. In this lesson, we will analyze such generics.
+
+The principle of generics does not change from the number of parameters. The only thing you need to keep an eye on is the names:
+
+```typescript
+type Double = {
+ first: T;
+ second: U;
+}
+
+const value: Double = {
+ first: 'code-basics',
+ second: 1,
+}
+```
+
+## Type inference from function arguments
+
+Let's imagine that we need to call a function with several parameters. The arguments are represented by generics.
+
+For example, the function `join()` can be described as follows:
+
+```typescript
+function join(coll1: (T | U)[], coll2: U[]): (T | U)[] {
+ return coll1.concat(coll2);
+};
+
+join([1, 2], ['one', 'two']); // [1, 2, 'one', 'two']
+```
+
+But TypeScript allows us to do this more easily and not have to specify types for all parameters:
+
+```typescript
+join([1, 2], ['one', 'two']); // [1, 2, 'one', 'two']
+```
+
+TypeScript will infer the types for the function parameters itself. This is called type inference from function arguments. In this case, TypeScript will infer the types `number` and `string` for the parameters `T` and `U` respectively.
+
+We will learn about TypeScript's built-in generics that have two parameters in the following lessons. In real programming, such generics are often found in application code, such as in React.
diff --git a/modules/40-generics/40-many-parameters/en/data.yml b/modules/40-generics/40-many-parameters/en/data.yml
new file mode 100644
index 0000000..c8ba999
--- /dev/null
+++ b/modules/40-generics/40-many-parameters/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Generics with multiple parameters
+tips:
+ - >
+ [Typescript Generics
+ Explained](https://rossbulat.medium.com/typescript-generics-explained-15c6493b510f)
diff --git a/modules/40-generics/40-many-parameters/ru/EXERCISE.md b/modules/40-generics/40-many-parameters/ru/EXERCISE.md
index ef4f37a..5c3a249 100644
--- a/modules/40-generics/40-many-parameters/ru/EXERCISE.md
+++ b/modules/40-generics/40-many-parameters/ru/EXERCISE.md
@@ -1,5 +1,5 @@
-Реализуйте описание обобщенного типа `MyMap`, который представляет из себя аналог ассоциативного массива из JavaScript. Пример использования объекта этого типа:
+Реализуйте описание обобщенного типа `MyMap`, который представляет собой аналог ассоциативного массива из JavaScript. Пример использования объекта этого типа:
```typescript
const map: MyMap = ...;
diff --git a/modules/40-generics/50-async-functions/en/EXERCISE.md b/modules/40-generics/50-async-functions/en/EXERCISE.md
new file mode 100644
index 0000000..7707577
--- /dev/null
+++ b/modules/40-generics/50-async-functions/en/EXERCISE.md
@@ -0,0 +1,10 @@
+
+Implement an asynchronous variant of the `map()` function - `asyncMap()`. The first argument of `asyncMap()` takes an array with Promise. The second is a function that is applied to each element. The function should return an array with the results of the function execution for each element:
+
+```typescript
+const promisedNumbers = [Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)];
+
+asyncMap(promisedNumbers, (num, index) => num * index).then((result) => {
+ console.log(result); // [0, 2, 6]
+});
+```
diff --git a/modules/40-generics/50-async-functions/en/README.md b/modules/40-generics/50-async-functions/en/README.md
new file mode 100644
index 0000000..bd01e0e
--- /dev/null
+++ b/modules/40-generics/50-async-functions/en/README.md
@@ -0,0 +1,44 @@
+
+`Promise` have become the most popular way to work with asynchronous code in JavaScript. They avoid the callback hell and also simplify working with asynchronous functions. TypeScript also supports the familiar async/await syntax and typing for working with Promise.
+
+```typescript
+const promise = new Promise((resolve, reject) => {
+ setTimeout(() => {
+ resolve(42);
+ }, 1000);
+});
+```
+
+`Promise` represents a generic with a type that will be returned if successful. In the example above, this is the type `number`.
+
+To continue working in the same style with functions that accept callback, we can promise them. To do this, we need to wrap the function in `Promise`:
+
+```typescript
+const wait = (ms: number): Promise => {
+ return new Promise((resolve) => {
+ const timer = setTimeout(() => {
+ resolve(ms);
+ }, ms);
+ });
+};
+```
+
+We don't have to describe the type of the return value, since TypeScript will be able to derive it from the type we pass to `Promise`. In addition, from a function that is marked as `async`, `Promise` is returned automatically, and the type of the return value will be wrapped in `Promise`:
+
+```typescript
+const getHours = async () => {
+ return new Date().getHours();
+};
+
+const hoursPromise: Promise = getHours();
+```
+
+Since `Promise`, like a container, wraps values within itself, we can use `await` to get a value from it:
+
+```typescript
+const hours = await getHours();
+```
+
+As in JavaScript in TypeScript `await` can only be used inside functions that are labelled as `async`.
+
+`Promise` together with `async/await` allow us to write asynchronous code in a synchronous style and greatly simplify the handling of asynchronous code. TypeScript supports this syntax and with generics allows us to use it with all the power of typing.
diff --git a/modules/40-generics/50-async-functions/en/data.yml b/modules/40-generics/50-async-functions/en/data.yml
new file mode 100644
index 0000000..d920438
--- /dev/null
+++ b/modules/40-generics/50-async-functions/en/data.yml
@@ -0,0 +1,8 @@
+---
+name: Asynchronous functions
+tips:
+ - >
+ [TypeScript Deep Dive:
+ Promise](https://basarat.gitbook.io/typescript/future-javascript/promise)
+ - >
+ [Awaited](https://www.typescriptlang.org/docs/handbook/utility-types.html#awaitedtype)
diff --git a/modules/40-generics/60-generic-classes/en/EXERCISE.md b/modules/40-generics/60-generic-classes/en/EXERCISE.md
new file mode 100644
index 0000000..6fd2fd8
--- /dev/null
+++ b/modules/40-generics/60-generic-classes/en/EXERCISE.md
@@ -0,0 +1,9 @@
+
+Implement a queue class (`Queue`) with `enqueue` and `dequeue` methods. The `enqueue` method adds an item to the end of the queue, and the `dequeue` method removes an item from the beginning of the queue. If the queue is empty, an `Error` exception must be thrown when the `dequeue` method is called:
+
+```typescript
+const queue = new Queue();
+queue.enqueue(1);
+queue.dequeue(); // 1
+queue.dequeue(); // Error: Queue is empty
+```
diff --git a/modules/40-generics/60-generic-classes/en/README.md b/modules/40-generics/60-generic-classes/en/README.md
new file mode 100644
index 0000000..10a7c23
--- /dev/null
+++ b/modules/40-generics/60-generic-classes/en/README.md
@@ -0,0 +1,58 @@
+
+Generic classes, like generic functions, allow you to create classes that can handle different data types. For example, a `Triple` class can store three values of any type. In this case, instead of creating classes for each type, you can create a generic class that will work with any data type.
+
+```typescript
+class Triple {
+ constructor(protected first: T, protected second: U, protected third: V) {}
+
+ getFirst(): T {
+ return this.first;
+ }
+
+ getSecond(): U {
+ return this.second;
+ }
+
+ getThird(): V {
+ return this.third;
+ }
+}
+```
+
+In this example, the `Triple` class is a generic class into which we can put any data types. In doing so, we still have the type safety guarantees and type inference that we got when using generalized functions:
+
+```typescript
+const triple = new Triple(1, 'string', null);
+const first = triple.getFirst(); // number
+const second = triple.getSecond(); // string
+```
+
+It is also possible to inherit from generalized classes. For example, the `Pair` class can be an inheritor of the `Triple` class, which stores two values of any type:
+
+```typescript
+class Pair extends Triple {
+ constructor(first: T, second: U) {
+ super(first, second, undefined as never);
+ }
+
+ getFirst(): T {
+ return this.first;
+ }
+
+ getSecond(): U {
+ return this.second;
+ }
+}
+```
+
+Here we have used a cast to type `never` to mark the third parameter as missing.
+
+Like ordinary classes, generalized classes can also be used as types of function parameters:
+
+```typescript
+function swap(pair: Pair): Pair {
+ return new Pair(pair.getSecond(), pair.getFirst());
+}
+```
+
+Generic classes are useful when we need to create some kind of container to store data, as in the `Pair` class example. `Array`, `Map`, `Set` are generic classes that store elements of a given type.
diff --git a/modules/40-generics/60-generic-classes/en/data.yml b/modules/40-generics/60-generic-classes/en/data.yml
new file mode 100644
index 0000000..cc62325
--- /dev/null
+++ b/modules/40-generics/60-generic-classes/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Generics in Classes
diff --git a/modules/40-generics/description.en.yml b/modules/40-generics/description.en.yml
new file mode 100644
index 0000000..a5b003c
--- /dev/null
+++ b/modules/40-generics/description.en.yml
@@ -0,0 +1,4 @@
+---
+name: Generics
+description: |
+ Generics allow you to write more versatile code that can work with different data types. TypeScript has a powerful generics system that allows you to create flexible yet robust parts of the system.
diff --git a/modules/50-objects/15-object/en/EXERCISE.md b/modules/50-objects/15-object/en/EXERCISE.md
new file mode 100644
index 0000000..85607a3
--- /dev/null
+++ b/modules/50-objects/15-object/en/EXERCISE.md
@@ -0,0 +1,12 @@
+
+Implement a `extract(object, keys)` function that returns a new object with the specified keys. For example:
+
+```typescript
+const user = {
+ name: 'Tirion',
+ email: 'tirion@lanister.got',
+ age: 35,
+}
+
+extract(user, ['name', 'age']); // { name: 'Tirion', age: 35 }
+```
diff --git a/modules/50-objects/15-object/en/README.md b/modules/50-objects/15-object/en/README.md
new file mode 100644
index 0000000..c6cb5e1
--- /dev/null
+++ b/modules/50-objects/15-object/en/README.md
@@ -0,0 +1,49 @@
+
+Sometimes we need to restrict the input parameter of a function to the type ‘any object’. For example, we need this for a function that checks for the presence of keys in an object. There are several ways to do this check, but not all of them work as expected.
+
+Let's look at an example:
+
+```typescript
+// {} is used as the type
+function toString(obj: {}) {
+ return obj.toString();
+}
+
+toString('wow'); // Ok!
+toString(123); // Ok!
+toString({}); // Ok!
+```
+
+An empty object type `{}` implies an object of any structure and restricts the set of all values except `null` and `undefined`. An empty interface works the same way as an empty object type. It is not what we would expect.
+
+The `Object` type is an object type. It works just like the `{}` type with some differences. It predefines the types of some built-in methods, such as `toString()`, while the `{}` type does not. For example:
+
+```typescript
+const foo: {} = {
+ toString() {
+ return 1; // Ok!
+ }
+};
+
+const bar: Object = {
+ toString() {
+ return 1; // Error!
+ }
+};
+```
+
+The second definition of `bar` doesn't work because the `Object` type specifies that the `toString()` method should return a string.
+
+If we want to work with non-primitive values, there is another type `object` (with a small letter) for that:
+
+```typescript
+function toString(obj: object) {
+ return obj.toString();
+}
+
+toString('wow'); // Error!
+toString(123); // Error!
+toString({}); // Ok!
+```
+
+With the help of `object` type it is impossible to get access to object properties. Other mechanisms are used for such a task.
diff --git a/modules/50-objects/15-object/en/data.yml b/modules/50-objects/15-object/en/data.yml
new file mode 100644
index 0000000..4a317eb
--- /dev/null
+++ b/modules/50-objects/15-object/en/data.yml
@@ -0,0 +1,2 @@
+---
+name: Type 'object'
diff --git a/modules/50-objects/15-object/ru/EXERCISE.md b/modules/50-objects/15-object/ru/EXERCISE.md
index 52afadd..5c13ab1 100644
--- a/modules/50-objects/15-object/ru/EXERCISE.md
+++ b/modules/50-objects/15-object/ru/EXERCISE.md
@@ -1,5 +1,5 @@
-Реализуйте функцию `extract(object, keys)`, которая возвращает новый объект c указанными ключами. Например:
+Реализуйте функцию `extract(object, keys)`, которая возвращает новый объект с указанными ключами. Например:
```typescript
const user = {
diff --git a/modules/50-objects/20-index-signatures/en/EXERCISE.md b/modules/50-objects/20-index-signatures/en/EXERCISE.md
new file mode 100644
index 0000000..285fb05
--- /dev/null
+++ b/modules/50-objects/20-index-signatures/en/EXERCISE.md
@@ -0,0 +1,14 @@
+
+Implement the `EmployeeSalary` interface, where the key is the name (`string`) and the value is the salary (`number`). Also implement the function `buildSalaryStatistics(employees: EmployeeSalary): SalaryStatistics`, which should return the minimum (`min` field), average (`avg` field) and highest (`max` field) salary.
+
+```typescript
+const employees: EmployeeSalary = {
+ mango: 100,
+ poly: 50,
+ ajax: 150,
+};
+
+employees.ironMan = 1000;
+
+buildSalaryStatistics(employees); // { min: 50, max: 1000, avg: 325 }
+```
diff --git a/modules/50-objects/20-index-signatures/en/README.md b/modules/50-objects/20-index-signatures/en/README.md
new file mode 100644
index 0000000..c3e353c
--- /dev/null
+++ b/modules/50-objects/20-index-signatures/en/README.md
@@ -0,0 +1,89 @@
+
+In JavaScript, we can use strings, numbers, and characters as keys in objects. TypeScript imposes the same restrictions on its object types. And we have to learn how to work with them.
+
+In this course, we have already worked with object types and with interfaces where field names are predefined. Now we will learn the syntax for dynamic keys:
+
+```typescript
+type dynamicKeysObject = {
+ [key: string | number | symbol]: unknown;
+};
+```
+
+Here we have declared an object type `dynamicKeysObject`, where the key can be any type from the available data types `key: string | number | symbol`. Let's try to specify such type for a variable:
+
+```typescript
+const obj: dynamicKeysObject = {
+ name: 'John',
+ age: 30,
+ 0: 'zero',
+ [Symbol('secret')]: 'symbol',
+};
+```
+
+Dynamic keys can also be used in conjunction with explicitly specified fields. In this case, the restrictions of dynamic fields will also apply to them:
+
+```typescript
+type MyTheme = {
+ palette: {
+ primary: 'red' | 'green' | 'blue';
+ [key: string]: string;
+ },
+ [key: string]: unknown;
+};
+
+const theme = {
+ palette: {
+ primary: 'red',
+ },
+ spacing: {
+ small: 8,
+ },
+} satisfies MyTheme;
+```
+
+In the example, we explicitly specified a type for the `palette` field, got a valid type check with `satisfies` and still left enough freedom to extend the topic further.
+
+The same syntax and behavior for dynamic keys in interfaces:
+
+```typescript
+interface MyTheme {
+ palette: {
+ primary: string;
+ };
+ [key: string]: unknown;
+}
+```
+
+In index classes signature can be used for both normal fields and `static` fields:
+
+```typescript
+class Template {
+ static [propName: string]: string | number;
+
+ [key: string]: string;
+}
+
+Template.test = 'test';
+
+const template = new Template();
+template.test = 'test';
+```
+
+## Template String Literal
+
+Dynamic keys are useful where we don't know all the possible field names of an object, but we still want to restrict their type. In TypeScript, a key type can also be a wildcard literal. For example, if we want to declare a listener type and require that all its methods start with the word `on`:
+
+```typescript
+type Listeners = {
+ [key: `on${string}`]: (value: unknown) => void
+}
+
+const streamListeners: Listeners = {
+ onStart() {},
+ onFinished() {}
+}
+```
+
+The ``on${string}`` literal type tells us that we expect a string based on the pattern ‘starts with `on` and any string thereafter’. This technique is called Template String Literal and is used to impose constraints when typing strings.
+
+If we look at a typical web application, we find that we know the structure of most objects from the beginning. Therefore, the use of dynamic keys can often be seen in libraries and in a number of auxiliary functions that we will look at in the following lessons.
\ No newline at end of file
diff --git a/modules/50-objects/20-index-signatures/en/data.yml b/modules/50-objects/20-index-signatures/en/data.yml
new file mode 100644
index 0000000..c05a9d2
--- /dev/null
+++ b/modules/50-objects/20-index-signatures/en/data.yml
@@ -0,0 +1,9 @@
+---
+name: Index Signature
+tips:
+ - >
+ [The chapter on Index Signature in the book TypeScript Deep
+ Dive](https://basarat.gitbook.io/typescript/type-system/index-signatures)
+ - >
+ [Official documentation on Template Literal
+ Types](https://www.typescriptlang.org/docs/handbook/2/template-literal-types.html)
diff --git a/modules/50-objects/30-mapped-types/en/EXERCISE.md b/modules/50-objects/30-mapped-types/en/EXERCISE.md
new file mode 100644
index 0000000..f81b042
--- /dev/null
+++ b/modules/50-objects/30-mapped-types/en/EXERCISE.md
@@ -0,0 +1,14 @@
+
+Implement the `sanitize()` function that takes an object and an array of keys as input. It should also return a new object, but without the specified fields.
+
+```typescript
+const user = sanitize({
+ name: 'John',
+ password: '1q2w3e',
+ token: 'test',
+}, ['password', 'token']); // { name: string }
+
+console.log(user); // => { name: 'John' }
+```
+
+Note that the output type should also not have these fields.
diff --git a/modules/50-objects/30-mapped-types/en/README.md b/modules/50-objects/30-mapped-types/en/README.md
new file mode 100644
index 0000000..ef9e3ce
--- /dev/null
+++ b/modules/50-objects/30-mapped-types/en/README.md
@@ -0,0 +1,86 @@
+
+To avoid duplication of fields when working with object types and to reuse existing ones, we can use the Lookup Types mechanism:
+
+```typescript
+interface Person {
+ name: string;
+ age: number;
+ location?: {
+ country: string;
+ city: string;
+ };
+}
+
+interface PersonDetails {
+ location: Person['location'];
+}
+```
+
+The `Type[Key]` construct looks and works just like getting an object's value by key in JavaScript. But point access won't work here.
+
+Lookup Types also allows you to get a union of types from an object by several known keys, combined with a vertical dash `|`:
+
+```typescript
+type User = {
+ id: number;
+ name: string;
+ email: string;
+}
+
+type UserFields = User['id' | 'name' | 'email']; // string | number
+```
+
+To get the union of all keys from an object, we can use the `keyof` operator.
+
+Let's simplify our example:
+
+```typescript
+type User = {
+ id: number;
+ name: string;
+ email: string;
+}
+
+type UserFields = User[keyof User]; // string | number
+```
+
+In order not to duplicate completely all fields of one object type, auxiliary types are used in another:
+
+* `Pick` - creates an object type with `Keys` keys from `Type`
+* `Omit` - creates an object type from which the `Keys` keys of `Type` are excluded
+
+```typescript
+interface Person {
+ name: string;
+ age: number;
+ location?: string;
+}
+
+const details: Pick = {
+ name: 'John',
+ age: 42,
+};
+
+const details2: Omit = {
+ name: 'John',
+ age: 42,
+};
+```
+
+In this example, the type resulting from `Pick` and `Omit` will be the same.
+
+All Utility Types in TypeScript are written using inline constructs. We have already learned enough TypeScript concepts to start dealing with them. So we may wonder how they are implemented.
+
+Let's look at how the `Pick` type is implemented:
+
+```typescript
+type Pick = {
+ [P in K]: T[P];
+};
+```
+
+`Pick` is a generic type with two parameters: `T` and `K`. On `K` we have also imposed the constraint `extends keyof T`. This means that `K` must contain an enumeration of keys from `T`.
+
+The `in` operator works here in the same way as in normal loops: it searches through all elements of the enumeration. In the example above, all elements in `K` are enumerated. At each iteration, `P` will contain the current element from `K`. Each such element of `P` becomes a key, and for the value we look for a suitable type in the object type `T[P]`.
+
+The operators `keyof` (Lookup Types) and `in` (Mapped Types) often go side by side. With `keyof` we access all the property names of an object type, and with `in` we can loop through all the properties. These operations are key when creating your own auxiliary types when working with object data types.
diff --git a/modules/50-objects/30-mapped-types/en/data.yml b/modules/50-objects/30-mapped-types/en/data.yml
new file mode 100644
index 0000000..b591075
--- /dev/null
+++ b/modules/50-objects/30-mapped-types/en/data.yml
@@ -0,0 +1,18 @@
+---
+name: Mapped Types
+tips:
+ - >
+ [Official documentation on Mapped
+ Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)
+ - >
+ [Official documentation on
+ keyof](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-1.html#keyof-and-lookup-types)
+ - >
+ [Understanding "keyof
+ typeof"](https://www.huy.rocks/everyday/04-14-2022-typescript-understanding-keyof-typeof-)
+ - >
+ [Official documentation on
+ Pick](https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys)
+ - >
+ [Official documentation on
+ Omit](https://www.typescriptlang.org/docs/handbook/utility-types.html#omittype-keys)
diff --git a/modules/50-objects/35-mapping-modifiers/en/EXERCISE.md b/modules/50-objects/35-mapping-modifiers/en/EXERCISE.md
new file mode 100644
index 0000000..acc0b29
--- /dev/null
+++ b/modules/50-objects/35-mapping-modifiers/en/EXERCISE.md
@@ -0,0 +1,15 @@
+
+Implement the `deepFreeze()` function that takes an object as input and makes it, its fields and all nested objects immutable and returns that object.
+Assume that the fields of the object and the fields of the nested objects do not contain arrays, only simple data types and objects.
+
+```typescript
+const user = deepFreeze({
+ name: 'John',
+ password: '1q2w3e',
+ token: 'test',
+});
+
+user.name = 'Alex'; // Error: Cannot assign to 'name' because it is a read-only property.
+```
+
+You need to use JavaScript's built-in [Object.freeze()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) method.
\ No newline at end of file
diff --git a/modules/50-objects/35-mapping-modifiers/en/README.md b/modules/50-objects/35-mapping-modifiers/en/README.md
new file mode 100644
index 0000000..d459d6b
--- /dev/null
+++ b/modules/50-objects/35-mapping-modifiers/en/README.md
@@ -0,0 +1,59 @@
+
+During type matching, you can change property attributes such as immutability and optionality. This is done using the corresponding modifiers: `readonly` and `?`.
+
+To add or remove these modifiers, you can use the prefixes `+` or `-`. If no prefix is used, it is assumed that the modifier will be added, i.e. the default prefix is `+`.
+
+Examples of using modifiers can be found in Utility Types:
+
+```typescript
+/**
+ * Makes all properties of type `T` optional,
+ * meaning it adds the `?` attribute.
+ */
+type Partial = {
+ [P in keyof T]?: T[P];
+};
+
+/**
+ * Makes all properties of type `T` mandatory,
+ * meaning it removes the `?` attribute.
+ */
+type Required = {
+ [P in keyof T]-?: T[P];
+};
+
+/**
+ * Makes all properties of type `T` immutable,
+ * meaning it adds the `readonly` attribute.
+ */
+type Readonly = {
+ readonly [P in keyof T]: T[P];
+};
+```
+
+Similarly, you can also write a type that makes all properties of the type modifiable, that is, it removes the `readonly` attribute:
+
+```typescript
+type Mutable = {
+ -readonly [P in keyof T]: T[P];
+};
+```
+
+Thanks to such types it is easier to create derived types from existing ones.
+
+For example, an application may have a `User` type for an unauthorized user with all fields not required:
+
+```typescript
+type User = {
+ id?: string;
+ firstName?: string;
+ secondName?: string;
+ email?: string;
+};
+```
+
+It can be made into an authorized user using the `Required` type:
+
+```typescript
+type AuthorizedUser = Required;
+```
diff --git a/modules/50-objects/35-mapping-modifiers/en/data.yml b/modules/50-objects/35-mapping-modifiers/en/data.yml
new file mode 100644
index 0000000..5466ef8
--- /dev/null
+++ b/modules/50-objects/35-mapping-modifiers/en/data.yml
@@ -0,0 +1,18 @@
+---
+name: Mapping Modifiers
+tips:
+ - >
+ [Official documentation on Mapped
+ Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)
+ - >
+ [Official documentation on Mapping
+ Modifiers](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers)
+ - >
+ [Official documentation on
+ Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype)
+ - >
+ [Official documentation on
+ Required](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype)
+ - >
+ [Official documentation on
+ Readonly](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype)
diff --git a/modules/50-objects/35-mapping-modifiers/ru/README.md b/modules/50-objects/35-mapping-modifiers/ru/README.md
index 1530cf3..fe59dbc 100644
--- a/modules/50-objects/35-mapping-modifiers/ru/README.md
+++ b/modules/50-objects/35-mapping-modifiers/ru/README.md
@@ -38,9 +38,9 @@ type Mutable = {
};
```
-Благодаря таким типам легче далеть производные типы из уже имеющихся.
+Благодаря таким типам легче делать производные типы из уже имеющихся.
-Например, в приложении может быть тип `User` для не авторизованного пользователя у которого все поля не обязательные:
+Например, в приложении может быть тип `User` для неавторизованного пользователя у которого все поля не обязательные:
```typescript
type User = {
diff --git a/modules/50-objects/45-record/en/EXERCISE.md b/modules/50-objects/45-record/en/EXERCISE.md
new file mode 100644
index 0000000..a9dcdc2
--- /dev/null
+++ b/modules/50-objects/45-record/en/EXERCISE.md
@@ -0,0 +1,21 @@
+
+Implement a `createAccessChecker()` function that takes an object with role permissions as input and returns a function that checks whether a user has access to a resource.
+
+```typescript
+type UserRole = 'admin' | 'user' | 'guest';
+type UserResource = 'document' | 'user' | 'adminPanel';
+
+const userRolePermissions: Record> = {
+ admin: ['document', 'user', 'adminPanel'],
+ user: ['document', 'user'],
+ guest: ['document'],
+};
+
+const checkUserAccess = createAccessChecker(userRolePermissions);
+
+const isAdminAllowed = checkUserAccess('admin', 'adminPanel');
+console.log(isAdminAllowed); // => true
+
+const isUserAllowed = checkUserAccess('user', 'adminPanel');
+console.log(isUserAllowed); // => false
+```
diff --git a/modules/50-objects/45-record/en/README.md b/modules/50-objects/45-record/en/README.md
new file mode 100644
index 0000000..b7e0262
--- /dev/null
+++ b/modules/50-objects/45-record/en/README.md
@@ -0,0 +1,27 @@
+
+Objects with dynamic structure, when we add fields to them at runtime, are often used to build context or store data. Let's write an auxiliary type to build such an object:
+
+```typescript
+type Context = {
+ [Key in K]: V;
+}
+
+const runApp = >(ctx: C) => {};
+```
+
+The `Key` key will accept all values from `K` by brute force. In turn, `K` is a subset of `string` and `V` can be any. So here we have created our own type `Context` with string fields and an unknown type for the value.
+
+This kind of construction, where we do not additionally define any specific fields with dynamic keys, is quite common. The built-in Utility Types provide a ready solution for this - `Record`. This generalized type takes a key type as its first argument and a value type as its second. Inside, everything is organized similarly as in our `Context` type:
+
+```
+type Rating = 0 | 1 | 2 | 3 | 4 | 5;
+type SongsRating = Record;
+
+const songsRating: SongsRating = {
+ ratata: 4,
+}
+```
+
+With this type `SongsRating` we can specify an object type with an arbitrary key (song name) and a rating - a number from zero to five.
+
+`Record` is more preferable when describing object types in TypeScript. It allows describing dynamic structures flexibly and concisely, and to use `Record` together with other data types.
diff --git a/modules/50-objects/45-record/en/data.yml b/modules/50-objects/45-record/en/data.yml
new file mode 100644
index 0000000..570e3d9
--- /dev/null
+++ b/modules/50-objects/45-record/en/data.yml
@@ -0,0 +1,6 @@
+---
+name: Records
+tips:
+ - >
+ [Record in Official
+ Documentation](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type)
diff --git a/modules/50-objects/description.en.yml b/modules/50-objects/description.en.yml
new file mode 100644
index 0000000..566fa95
--- /dev/null
+++ b/modules/50-objects/description.en.yml
@@ -0,0 +1,5 @@
+---
+
+name: Object Typing
+description: |
+ Objects in TypeScript can be described using interfaces and types. In this section, we will look at the peculiarities of typing objects, obtaining dynamic properties, and the peculiarities of defining object types.
diff --git a/modules/ignored_languagetool_errors b/modules/ignored_languagetool_errors
new file mode 100644
index 0000000..2828f2f
--- /dev/null
+++ b/modules/ignored_languagetool_errors
@@ -0,0 +1,420 @@
+README.md:28:43:14
+.... ## See most active contributors on [hexlet-friends](https://friends.hexlet.io/).
+Possible spelling mistake found.
+Предлагаемые варианты:
+hex let-friends
+------------------------
+modules/35-interfaces/30-interface-implementation/en/README.md:16:43:11
+...we create an interface or type and then transpilate TypeScript into JavaScript, there will ...
+Possible spelling mistake found.
+Предлагаемые варианты:
+translate
+------------------------
+modules/35-interfaces/30-interface-implementation/en/README.md:16:43:10
+...we create a class, its sample is always transpiled into JavaScript. It turns out that the...
+Possible spelling mistake found.
+Предлагаемые варианты:
+transpired
+------------------------
+modules/35-interfaces/20-interface-using/en/EXERCISE.md:1:43:9
+...l interfaces. Based on them, create the ISuperman interface. ISuperMan must have a guessW...
+Possible spelling mistake found.
+Предлагаемые варианты:
+Superman, I Superman
+------------------------
+modules/35-interfaces/20-interface-using/en/EXERCISE.md:1:43:9
+...n them, create the ISuperman interface. ISuperMan must have a guessWho method that accept...
+Possible spelling mistake found.
+Предлагаемые варианты:
+Superman
+------------------------
+modules/35-interfaces/20-interface-using/en/EXERCISE.md:1:43:8
+...perman interface. ISuperMan must have a guessWho method that accepts and returns a strin...
+Possible spelling mistake found.
+Предлагаемые варианты:
+guess Who
+------------------------
+modules/35-interfaces/20-interface-using/en/EXERCISE.md:3:43:9
+...pts and returns a string. Based on the ISuperMan interface, create a `` object. The gues...
+Possible spelling mistake found.
+Предлагаемые варианты:
+Superman
+------------------------
+modules/35-interfaces/20-interface-using/en/EXERCISE.md:3:43:8
+...rMan interface, create a `` object. The guessWho method should work as follows: if any v...
+Possible spelling mistake found.
+Предлагаемые варианты:
+guess Who
+------------------------
+modules/35-interfaces/10-interfaces-overview/ru/EXERCISE.md:1:43:19
+...станцию. Также у класса Car должна быть функция-конструктор, которая принимает и реализует свойства...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/35-interfaces/10-interfaces-overview/en/README.md:37:43:9
+...eature is called subtype polymorphism ([Subtyping](https://en.wikipedia.org/wiki/Subtypin...
+Possible spelling mistake found.
+------------------------
+modules/35-interfaces/10-interfaces-overview/en/EXERCISE.md:1:18:8
+You are given the IVehicle interface. The task is to implement a C...
+Possible spelling mistake found.
+Предлагаемые варианты:
+Vehicle, I Vehicle
+------------------------
+modules/35-interfaces/10-interfaces-overview/en/EXERCISE.md:1:43:14
+...ed on this interface, which will have a calcFuelNeeded method that accepts the distance in kil...
+Possible spelling mistake found.
+------------------------
+modules/50-objects/20-index-signatures/ru/README.md:13:43:9
+...ния кода: на что обратить внимание, что сделали--> Динамические ключи можно также исполь...
+Возможно найдена орфографическая ошибка.
+Предлагаемые варианты:
+сделали, сделались
+------------------------
+modules/50-objects/20-index-signatures/ru/README.md:27:43:9
+...ния кода: на что обратить внимание, что сделали--> В классах index signature можно испол...
+Возможно найдена орфографическая ошибка.
+Предлагаемые варианты:
+сделали, сделались
+------------------------
+modules/50-objects/15-object/ru/README.md:17:43:14
+...ащать строку. Если мы хотим работать с непримитивными значениями, то для этого существует еще...
+Возможно найдена орфографическая ошибка.
+Предлагаемые варианты:
+не примитивными
+------------------------
+modules/40-generics/60-generic-classes/ru/README.md:1:0:15
+Дженерик-классы, как и дженерик функции, позволяют созд...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/40-generics/60-generic-classes/ru/README.md:8:43:14
+...pescript ``` В этом примере класс `` — дженерик-класс, в который мы можем поместить любые тип...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/40-generics/60-generic-classes/ru/README.md:29:43:15
+...тить внимание, или что тут сделали --> Дженерик-классы полезны, когда нам нужно создать какой-...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/40-generics/60-generic-classes/ru/README.md:29:43:15
+... примере с классом ``. ``, ``, `` — это дженерик-классы, которые хранят элементы заданного типа...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/40-generics/40-many-parameters/ru/EXERCISE.md:6:43:18
+...ода `` и ``. Первый метод принимает два дженерик-параметра: ключ и значение. Второй метод принимае...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/40-generics/50-async-functions/ru/README.md:10:43:16
+...и, которые принимают callback, мы можем промисифцировать их. Для этого нам нужно обернуть функци...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/40-generics/20-generic-types/en/README.md:12:43:4
+...res. Such collections are often made in ORMs to work with data loaded from a databas...
+Possible spelling mistake found.
+Предлагаемые варианты:
+Arms, Forms, Norms, Worms, RMS, Ores, Dorms, Ohms, Orbs, Orcs, Corms, Oms, DRMs, HRMS, ODMs, OEMs, OMMS, OMS, ORM, ORMA, ORS, ORUs, ROMs, OR Ms
+------------------------
+modules/30-classes/30-class-extending/en/README.md:17:43:9
+...eter types of the overridden method are bivariant * The return type of the overridden met...
+Possible spelling mistake found.
+------------------------
+modules/25-types/70-variability/ru/README.md:3:43:18
+...дим возвращающую `` функцию для колбека функции-сортировки, которая ожидает возврата ``, то получи...
+Возможно найдена орфографическая ошибка.
+------------------------
+modules/25-types/70-variability/ru/README.md:34:43:2
+...может быть шире, а тип на выходе — уже. В примере formatToConcrete не принимает ...
+Повтор пробела
+Предлагаемые варианты:
+
+------------------------
+modules/25-types/70-variability/en/README.md:24:43:14
+...This type checking behavior is called **contravariance**. Try to explain the behavior of type...
+Possible spelling mistake found.
+Предлагаемые варианты:
+contra variance
+------------------------
+modules/25-types/70-variability/en/README.md:34:43:2
+...er and the output type can be narrower. In the example, formatToConcrete takes n...
+Possible typo: you repeated a whitespace
+Предлагаемые варианты:
+
+------------------------
+modules/25-types/70-variability/en/README.md:34:43:16
+...type can be narrower. In the example, formatToConcrete takes no parameters. This gives a wider...
+Possible spelling mistake found.
+------------------------
+modules/25-types/70-variability/en/README.md:34:43:14
+...And it returns a narrower literal type. formatToNumber expects a narrower type on the input, t...
+Possible spelling mistake found.
+------------------------
+modules/25-types/60-structural-typing/ru/README.md:12:43:10
+...ой типизации. С ней мы и познакомимся в этой уроке. С помощью структурной типизации мы мо...
+Притяжательное прилагательное (местоимение) не согласуется с существительным по роду.
+Предлагаемые варианты:
+этом уроке
+------------------------
+modules/25-types/60-structural-typing/ru/README.md:32:43:23
+...еньше полей в объектном типе, тем менее специфичное ограничений накладывается на присваиваемое значение...
+Прилагательное не согласуется с существительным по падежу.
+Предлагаемые варианты:
+специфичного ограничений
+------------------------
+modules/25-types/60-structural-typing/ru/EXERCISE.md:1:43:2
+...троку в зависимости от состояния: `` при ``, `` при ``, строку из числового поля ...
+Повтор пробела
+Предлагаемые варианты:
+
+------------------------
+modules/25-types/50-type-hierarcy/en/README.md:63:43:14
+...g picture of TypeScript's type sets: : ```typescript ``` ...
+Возможно найдена орфографическая ошибка.
+Предлагаемые варианты:
+присваиваем остью
+------------------------
+modules/25-types/40-assignability/ru/README.md:10:43:15
+... о типах, как о множествах значений, то присваиваемость — это проверка, что множество значений ...
+Возможно найдена орфографическая ошибка.
+Предлагаемые варианты:
+присваиваем ость
+------------------------
+modules/25-types/30-intersection-types/en/README.md:14:43:14
+...t fit the constraints of both types. . This language construct allows you to...
+Possible spelling mistake found.
+Предлагаемые варианты:
+ends, enemy, genus, drums, venues, Venus, exams, nuns, nuts, sums, ensues, menus, slums, gums, plums, elms, numb, onus, Enos, alums, bums, emus, enema, enema
+s, chums, hums, rums, snubs, nubs, nus, serums, arums, denims, ecus, ems, numbs, plenums, Tums, begums, gnus, scums, snugs, benumb, endues, tums, EN3S, ENIM,
+ ENM, ENS, ENSM, ENSMA, ENSMM, ENSMN, ENSMSE, ENSPS, EOMs, ERTMS, ETFMS, EUS, Edams, Equus, NUMA, NUS, UMS, anus, benumbs, cums, ens, fums, écus, étuis
+------------------------
+modules/10-basics/60-enums/en/README.md:5:43:5
+...a set of names and then refer to them. Enums are used in place of strings for consta...
+Possible spelling mistake found.
+Предлагаемые варианты:
+Ends, Enemy, Genus, Drums, Venues, Venus, Exams, Nuns, Nuts, Sums, Ensues, Menus, Slums, Gums, Plums, Elms, Numb, Onus, Enos, Alums, Bums, Emus, Enema, Enema
+s, Chums, Hums, Rums, Snubs, Nubs, Nus, Serums, Arums, Denims, Ecus, Ems, Numbs, Plenums, Tums, Begums, Gnus, Scums, Snugs, Benumb, Endues, EN3S, ENIM, ENM, ENS, ENSM, ENSMA, ENSMM, ENSMN, ENSMSE, ENSPS, EOMs, ERTMS, ETFMS, EUS, Edams, Equus, NUMA, NUS, UMS, Anus, Benumbs, Cums, Ens, Fums, Écus, Étuis
+------------------------
+modules/10-basics/60-enums/en/README.md:10:43:5
+...cript ``` The most common use case for enums is storing different statuses. But ther...
+Possible spelling mistake found.
+Предлагаемые варианты:
+ends, enemy, genus, drums, venues, Venus, exams, nuns, nuts, sums, ensues, menus, slums, gums, plums, elms, numb, onus, Enos, alums, bums, emus, enema, enema
+s, chums, hums, rums, snubs, nubs, nus, serums, arums, denims, ecus, ems, numbs, plenums, Tums, begums, gnus, scums, snugs, benumb, endues, tums, EN3S, ENIM,
+ ENM, ENS, ENSM, ENSMA, ENSMM, ENSMN, ENSMSE, ENSPS, EOMs, ERTMS, ETFMS, EUS, Edams, Equus, NUMA, NUS, UMS, anus, benumbs, cums, ens, fums, écus, étuis
+------------------------
+modules/10-basics/60-enums/en/README.md:20:43:4
+...he week * Months ```typescript ``` An enum is both a value and a type. It can be s...
+Possible spelling mistake found.
+Предлагаемые варианты:
+ENIM, ENM, ENSM
+------------------------
+modules/10-basics/60-enums/en/README.md:25:43:5
+...n parameters: ```typescript ``` Also, enums are turned into a JavaScript object aft...
+Possible spelling mistake found.
+Предлагаемые варианты:
+ends, enemy, genus, drums, venues, Venus, exams, nuns, nuts, sums, ensues, menus, slums, gums, plums, elms, numb, onus, Enos, alums, bums, emus, enema, enema
+s, chums, hums, rums, snubs, nubs, nus, serums, arums, denims, ecus, ems, numbs, plenums, Tums, begums, gnus, scums, snugs, benumb, endues, tums, EN3S, ENIM,
+ ENM, ENS, ENSM, ENSMA, ENSMM, ENSMN, ENSMSE, ENSPS, EOMs, ERTMS, ETFMS, EUS, Edams, Equus, NUMA, NUS, UMS, anus, benumbs, cums, ens, fums, écus, étuis
+------------------------
+modules/10-basics/20-typescript-as-a-second-language/ru/README.md:51:43:13
+...pt. Этот процесс еще принято называть **транспиляцией** * Разработчик TypeScript — Microsoft ...
+Возможно найдена орфографическая ошибка.
+Предлагаемые варианты:
+трансляцией, транспирацией
+------------------------
+modules/10-basics/20-typescript-as-a-second-language/ru/README.md:84:43:4
+...яцию и запуск. Этот пакет предоставляет репл для экспериментов с TypeScript. ## Выв...
+Возможно найдена орфографическая ошибка.
+Предлагаемые варианты:
+реал, репа, реп, репе, репс, репу, репы, реял, риал, рил, рип, рипа, рипе, рипп, рипу, рипы, сипл, ре пл, реп л
+------------------------
+modules/10-basics/20-typescript-as-a-second-language/en/README.md:55:43:13
+...t code. This process is also known as **transpilation**. * The developer of TypeScript is Mic...
+Possible spelling mistake found.
+Предлагаемые варианты:
+transpiration
+------------------------
+modules/10-basics/20-typescript-as-a-second-language/en/README.md:74:43:10
+...is written in TypeScript, which is then transpiled into JavaScript and distributed as a no...
+Possible spelling mistake found.
+Предлагаемые варианты:
+transpired
+------------------------
+modules/10-basics/20-typescript-as-a-second-language/en/README.md:74:43:3
+... JavaScript and distributed as a normal npm package. The installation of TypeScript...
+Possible spelling mistake found.
+Предлагаемые варианты:
+NPM, PM, pm, rpm, NP, NPC, NPR, RPM, ppm, NPA, NPS, Nam, APM, BPM, CPM, NPD, TPM, LPM, GPM, wpm, EPM, FPM, IPM, MPM, NAM, NCM, NEM, NKM, NM, NMM, NP0, NPF, N
+PG, NPI, NPL, NPN, NPO, NPP, NPV, NRM, NSM, NVM, Np, OPM, PPM, Pm, QPM, SPM, XPM, bpm, nm, n pm, not, him, new, name, no, now, up, km, non, FM, NFL, am, arm,
+ cm, com, mm, nor, IBM, Jim, PA, PC, Tom, mph, net, sum, CPU, NSW, Sam, gym, neo, norm, rim, spy, ups, GPS, HP, MP3, NFC, NGO, NHS, NRL, NYC, PR, PT, RAM, RP
+G, dam, gum, nun, nut, opt, pH, ram, spa, ACM, APA, APC, ATM, BNP, CPA, CPC, CPI, CPR, DM, DRM, DSM, EPs, GPA, GPL, Ham, IPA, IPO, JP, LPs, NAD, NBL, NEC, NG
+C, NMR, NSA, NYPD, Nov, OEM, PD, PPP, PV, SAM, SNP, SPD, VP, WPA, amp, ape, apt, cam, dim, elm, gem, ham, mom, nod, nu, pa, pi, rum, spam, APG, APS, BPA, CPP
+, DTM, EPP, FP, GNP, GPO, GPU, HPV, IPC, IPS, KLM, KTM, LPG, MPA, MPH, MPP, NAC, NCA, NCO, NCR, NDA, NEA, NLP, NPCs, NRA, NRC, NSF, Napa, Nat, PCM, PJ, PNP,
+PPD, PPI, Pa, Pam, REM, RPC, RPF, SPL, UPC, UPI, UPS, VM, VPN, hum, mum, nape, nee, nil, ops, um, yam, ABM, AFM, APD, Apr, BPD, BRM, CBM, CPE, CPO, CTM, DCM,
+ DPI, DWM, EAM, EPG, ERM, FSM, GPC, ICM, IOM, IPN, IPP, IPR, JDM, JM, JVM, LSM, MPR, MPV, NBS, NCI, NDC, NEP, NFPA, NFS, NIR, NIV, NLS, NRG, NRI, NTP, NWT, N
+Y, Nome, PMA, PMC, PMI, PMR, PMS, PSM, PW, RCM, RPA, RPI, RPO, RPR, RSM, SNPs, SPF, SRM, SSM, TCM, TPA, TPC, Ulm, bum, hem, imp, mpg, nap, nay, numb, ohm, pp
+b, pt, rem, tam, APB, APN, Adm, BIM, CPF, DLM, DPD, DPT, EPL, FAM, FPA, GAM, GBM, IPI, KVM, LCM, LPO, LPP, MDM, MNP, NAL, NDB, NFF, Noe, PNM, PX, Qom, RPN, R
+PT, SDM, SGM, Spam, aim, fem, fps, gm, mp, nag, nip, nth, tum, yum, DPN, DPs, DVM, EPF, FPO, GPV, LPN, MPE, NLR, NVR, Nev, RMM, TPL, TPN, UAM, WLM, bam, bps,
+ dBm, nab, nae, naps, nit, nix, nub, pk, PMs, app, fum, kph, mam, neg, nips, nus, opp, vim, Jpn, nob, nope, GM, IP, Kim, MPs, NBA, NBC, NDP, NHL, Ned, PS, RO
+M, Tim, chm, cpl, dpt, jam, née, op, rps, cpd, ppr, 2RM, A&M, A6M, AAM, ADM, AEM, AGM, AGPM, AHM, AIM, AKM, ALM, AM, AMM, ANM, ANP, ANPE, ANPN, ANPS, ANSM, A
+OM, AP, APE, APF, APH, API, APJ, APK, APL, APO, APP, APQ, APR, APT, APU, APV, APW, APX, APY, APZ, APs, AQM, ARM, ASM, AUM, AVM, AWM, AXM, Am, B2M, BAM, BBM,
+BCM, BDM, BEM, BFM, BGM, BHM, BIPM, BJM, BKM, BLM, BM, BMM, BNM, BOM, BP, BPB, BPC, BPF, BPG, BPH, BPI, BPK, BPL, BPMG, BPMs, BPN, BPO, BPP, BPR, BPS, BPT, B
+PU, BPY, BSM, BTM, BUM, BVM, BWM, BXM, BYM, CAM, CCM, CDM, CEM, CFM, CGM, CHM, CIM, CKM, CLM, CM, CMM, CNAM, CNM, CNP, CNPC, CNPE, CNPN, CNPS, COM, CP, CPAM,
+ CPD, CPG, CPH, CPJ, CPL, CPMs, CPN, CPQ, CPS, CPT, CPV, CQM, CRM, CSM, CUM, CVM, CWM, CXM, CYM, CZM, Cm, Com, Cpl, DDM, DEM, DFM, DHM, DMM, DNP, DOM, DP, DP
+A, DPB, DPC, DPE, DPH, DPMI, DPO, DPS, DPU, DPW, DXM, Dem, ECM, EDM, EEM, EM, EMM, ENIM, ENM, ENP, ENPC, ENSM, ENSPM, EOM, EP, EPA, EPCM, EPI, EPO, EPR, EPS,
+ EPSM, EPT, EPU, EPV, EQM, ESM, ETM, EVM, FBM, FCM, FDM, FEM, FFM, FFPM, FGM, FHM, FIM, FKM, FLM, FMM, FNPC, FNPF, FPD, FPF, FPH, FPJ, FPP, FPR, FPS, FPT, FP
+U, FPV, FPs, FRM, FTM, Fm, GCM, GDM, GEM, GHM, GLM, GP, GPE, GPG, GPP, GPR, GPT, GPX, GPZ, GQM, GSM, GTM, GUM, H&M, HBM, HDM, HLM, HM, HOM, HPA, HPC, HPD, HP
+E, HPL, HPR, HPS, HRM, HSM, IDM, IEM, IFM, IGM, IIM, IJM, ILM, IM, INM, INP, INPP, INPT, IPAM, IPB, IPD, IPE, IPF, IPG, IPJ, IPT, IPY, IPs, IRM, ISM, JIM, JL
+M, JMM, JPA, JPF, JPG, JPN, JPO, JPP, JPR, JPX, JPY, Jem, KEM, KFM, KGM, KHM, KM, KNM, KP, KPD, KPF, KPI, KPL, KPMG, KPN, KPU, KPW, KSM, LBM, LEM, LFM, LGM,
+LIM, LKM, LNPA, LP, LPC, LPD, LPE, LPF, LPI, LPJ, LPQ, LPR, LPS, LRM, Lim, M, M&M, M2M, MAM, MCM, MFM, MGM, MIM, MKM, MLM, MM, MMM, MOM, MP, MP4, MPC, MPD, M
+PI, MPL, MPN, MPS, MPT, MPX, MSM, MZM, N, N10, N11, N12, N13, N14, N15, N16, N17, N18, N19, N20, N21, N22, N23, N24, N25, N26, N27, N28, N29, N30, N31, N32,
+N33, N34, N35, N40, N41, N42, N43, N44, N45, N48, N49, N50, N51, N52, N53, N61, N62, N63, N64, N70, N71, N72, N73, N74, N75, N76, N77, N78, N79, N80, N81, N8
+2, N85, N86, N90, N91, N92, N93, N95, N96, N97, N99, NAB, NAF, NAG, NAH, NAK, NAMC, NAO, NAP, NAS, NAU, NB, NBB, NBF, NBG, NBN, NBR, NBT, NC, NCB, NCC, NCD,
+NCE, NCL, NCP, NCQ, NCS, NCT, NCW, NCY, ND, NDF, NDH, NDK, NDMP, NDR, NDS, NDT, NE, NED, NEE, NEH, NEN, NER, NF, NF3, NFT, NG, NGA, NGE, NGN, NGS, NH, NHA, N
+HC, NHD, NHF, NHK, NHN, NI, NIA, NIB, NIC, NID, NIF, NIG, NIH, NIN, NIO, NIU, NJ, NJG, NJP, NK, NL, NLB, NLD, NLG, NLH, NLO, NLT, NLU, NMA, NMC, NMF, NMI, NM
+PP, NMT, NNI, NNN, NO, NOA, NOE, NOI, NOK, NON, NOPD, NOR, NOS, NOU, NOW, NOX, NPAG, NPAI, NPHC, NPNS, NPOV, NQY, NR, NRF, NRH, NRN, NRO, NRP, NRS, NRT, NRU,
+ NRW, NS, NSB, NSBM, NSC, NSS, NST, NSU, NT, NTC, NTD, NTI, NTL, NTPs, NTR, NTS, NTV, NTW, NU, NUI, NUMA, NUS, NUT, NV, NVA, NVMe, NVP, NVT, NW, NWD, NYH, NY
+K, NYS, NYT, NYU, NYX, NZ, NZD, NZL, Na, Nan, Nb, Nd, Ne, Neb, Nemo, Neo, Ni, No, Nos, Nye, O&M, OAM, ODM, OGM, OHM, OIM, OM, OMM, ONEM, ONM, ONP, OOM, OPA,
+OPG, OPI, OPK, OPL, OPML, OPO, OPQ, OPT, ORM, OSM, OVPM, P, PAM, PB, PE, PEM, PG, PGM, PH, PIM, PK, PL, PLM, PMB, PMD, PME, PMF, PMG, PMH, PML, PMN, PMO, PMP
+, PMT, PMU, PMV, PO, POM, PP, PP1, PP2, PP3, PP4, PP7, PPA, PPB, PPC, PPCM, PPE, PPH, PPK, PPL, PPN, PPO, PPQ, PPR, PPS, PPT, PPU, PPV, PQ, PRM, PTM, PU, PUM
+, PVM, PWM, Pb, Pd, Pl, Po, Pr, Pt, Pu, Pym, QCM, QM, QPC, QPO, QPV, RBM, RDM, RFM, RIM, RM, RP, RPB, RPD, RPE, RPK, RPP, RPS, RPU, RPV, RPX, RTM, RVM, Rom, SBM, SCM, SEM
\ No newline at end of file