> For the complete documentation index, see [llms.txt](https://race-timo.gitbook.io/typescript/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://race-timo.gitbook.io/typescript/classes.md).

# Классы

## Немного о классах

Долгое время в JavaScript для создания однотипных объектов использовалась функция-конструктор. Функция-конструктор вызывается при помощи оператора `new`. Эта функция заполняет полями и методами какой-то объект (обычно `this`) и возвращает его (явно или не явно).

```javascript
function Cat(name) {
    this.name = name;
    this.say = function() {
        console.log(this.name, "say:", "meow");
    }
}

const cat1 = new Cat("Tom");
const cat2 = new Cat("Lalaka");
cat1.say();
cat2.say();
```

В ES6 появился синтаксис, который позволяет объявлять классы. По сути класс - это функция-конструктор каких-то объектов с упрощенным синтаксисом наследования, объявления методов и еще некоторыми особенностями. Само понятие класса лучше отражает объектно-ориентированный подход разработки, чем использование функций-конструкторов и прототипов.

```javascript
class Cat {
    constructor(name) {
        this.name = name;
    }

    say() {
        console.log(this.name, "say:", "meow");
    }
}

const cat1 = new Cat("Tom");
const cat2 = new Cat("Lalaka");
cat1.say();
cat2.say();
```

Когда объявляется класс, в память кладется некоторый объект, который умеет создавать новые объекты при помощи оператора `new`. Объект класса - это функция конструктор, в котором хранится логика по заполнению новых других объектов. Объекты, которые были созданы при помощи какого-то класса называются экзэмплярами или инстансами (instance) этого класса.

Важно научится четко различать, что такое "объект класса" и "инстанс класса". Выше сказано, что объект класса - это объект в памяти (это функция). Это означает, что с объектом класса можно работать как с обычным объектам: добавлять поля, присваивать в качестве значения переменной, передавать в параметры функции (и в параметры конструктора другого класса).

```javascript
class Cat {
    constructor(name) {
        this.name = name;
    }
}

const obj = Cat;
const cat1 = new obj("Tom");

function create(classObj) {
    return new classObj("Tom");
}

const cat2 = create(Cat);

Cat.foo = function() {
    console.log("Функция у объекта класса");
}

Cat.foo();
```

Инстансы класса - это самостоятельные объекты, которые были сконструированы этого класса. Они не зависят друг от друга (если это не сделано специально) и с классом их связывает только то, что он являлся их создателем.

Объявление классов в TypeScript имеет ряд особенностей по сравнению с объявлением классов в JavaScript.

## Поля классов

Класс может иметь поля. Для того, чтобы объявить поле, нужно указать его название и тип.

```typescript
class A {
    b: number;
    c: string;
    e: { a: number; b: string };
}
```

Поля могут иметь модификатор доступа. В TypeScript существует 3 модификатора доступа:

* `public` - поле является публичным. Читать и изменять значение этого поля можно в любом месте
* `private` - поле является приватным. Читать и изменять значение этого поля можно только из методов самого класса
* `protected` - поле является защищенным. Чистать и изменять значение этого поля можно из методов самого класса и его наследников

```typescript
class A {
    public a: number;
    private b: string;
    protected c: boolean;
}

const a = new A();

a.a = 10;
a.b = "lalaka"; //Error: Property 'b' is private and only accessible within class 'A'.
a.c = true; //Error: Property 'c' is protected and only accessible within class 'A' and its subclasses.

const q1 = a.a;
const q2 = a.b; //Error: Property 'b' is private and only accessible within class 'A'.
const q3 = a.c; //Error: Property 'c' is protected and only accessible within class 'A' and its subclasses.
```

Модификаторы доступа полей нужны для того, чтобы правильно инкапсулировать логику внутри класса. `private` и `protected` поля хранят внутренне состояние класса. Это позволяет классу гарантировать, что значения в этих полях будут соответствовать внутренней логике класса (или потомка). Важно, что защита полей присутствует только на этапе компиляции. В JavaScript нет (пока) модификаторов доступа полей класса, поэтому в runtime значения приватных полей может быть изменено откуда угодно.

Если у поля не задан никакой модификатор доступа, то это поле `public` по умолчанию.

Для того, чтобы поле было доступно только на чтение, в TypeScript существует модификатор поля `readonly`. Он может применятся в месте с модификатором доступа. `readonly` поле должно быть инициализировано либо во время объявления, либо в конструкторе (об этом позже).

```typescript
class A {
    public readonly a: number = 10;
    private readonly b: string;

    constructor() {
        this.b = "lalaka";
    }
}

const a = new A();

const q1 = a.a;
a.a = q1; //Error: Cannot assign to 'a' because it is a read-only property.
```

Поле класса может быть статичным. Статичное поле - это поле, значение которого хранится не в каждом конкретном инстансе класса (у каждого свое), а в самом объекте класса. Статичное поле помечается модификатором `static`. К статичному полю можно применять модификаторы доступа и модификатор `readonly`.

```typescript
class A {
    static readonly a: { p: string } = { p: "lalaka" };
    private static readonly c: string = "lalaka";
}

const q1 = A.a; //q1 = { p: "lalaka" }
A.a.p = "malaka"; //A.a = { p: "malaka" }
q1.p; //q1 = { p: "malaka" }
```

Важно отметить, что к статичному полю через инстанс класса доступа нет.

```typescript
new A().a //Error: Property 'a' is a static member of type 'A'
```

Из-за того, что статичные поля присваиваются только объекту самого класса, а не статичные - только инстансу класса, в TypeScript можно объявить у одного и того же класс статичное и не статичное поля с одинаковым именем:

```typescript
class A {
    static a: number = 10;
    a: boolean = true;
}

A.a // 10
new A().a // true
```

Поля класса могут быть необязательными. Для этого после названия параметра нужно указать символ `?` (как у объектов).

## Конструктор

Выше уже было показано, как объявляется конструктор класса. Конструктор класса - это функция, которая вызывается для создания нового инстанса класса. Конструктор объявляется при помощи ключевого слова `constructor`. В конструкторе можно изменять значения полей класса (как публичных, так и приватных).

```typescript
class A {
    private a: number;
    public b: string;
    constructor() {
        this.a = 10;
        this.b = "lalaka";
    }
}
```

Ключевое слово `this` ссылается на тот инстанс класса, который сейчас конструируется. Этот же инстанс класса вернется в результате команды `new A()`. Конструктор класса - это функция. Она может принимать параметры. Параметры конструктора типизируются также, как типизируются параметры обычной функции.

```typescript
class A {
    private a: number;
    private b: string;
    private c?: boolean;
    constructor(a: number, b = "lalaka", c?: boolean) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
}

const a1 = new A(10);
const a2 = new A(15, "malaka");
const a3 = new A(20, "balaka", false);
```

Выше также было указано, что поля класса можно инициализировать во время объявления (in-place).

```typescript
class A {
    private a: number = 10;
}
```

При создании инстанса класса, in-place поля инициализируются до вызова конструктора. К их значениям можно получить доступ из конструктора. Также в конструкторе можно изменить in-place значение поля.

```typescript
class A {
    private a: number = 10;
    public b: number = 100;

    constructor() {
        this.b = this.a
    }
}

new A().b // 10
```

Для удобства работы в TypeScript есть возможность объявлять поля сразу в конструкторе класса. Если параметру конструктора указать модификатор доступа, то у класс появится поле с именем и значением параметра и указанным модификатором доступа:

```typescript
class A {
    constructor(private a: number, public b: string) {
    }
}

const q1 = new A(10, "lalaka");
q1.b // "lalaka"
```

## Методы

Помимо полей, класс может иметь методы. Метод класс - это функция, которая существует в рамках инстанса класса (статичная в рамках объекта класса). Эта функция имеет доступ к внутреннему состоянию класса. Она, как и другие функции, может иметь или не иметь возвращаемое значение и параметры класса (объявлять generic-параметры).

```typescript
class A {
    private q: number = 2;

    multiply(a: number): number {
        return this.q*a;
    }
}

const a = new A();
const q1 = a.multiply(15); // 30
const q2 = a.multiply(10); // 20
```

Методы класса могут иметь модификаторы доступа. Они такие же, как и модификаторы доступа полей. `public` методы могут быть вызваны, как внутри класса, так и снаружи; `private` - только внутри класса; `protected` - внутри класса или внутри класса наследника.

```typescript
class A {
    public say() {
        console.log(this.getWord("Hello"));
    }

    private getWord(word: string): string {
        return word;
    }
}

const a = new A();
a.say();
a.getWord("lalaka"); //Error: Property 'getWord' is private and only accessible within class 'A'.
```

Модификатор `readonly` к методам не применим. А вот модификатор `static` применим и работает похожим образом, как и для полей. Метод присваивается не инстансам класса, а самому объекту класса. Соответственно, статичный метод **не имеет** доступа к полям инстансов класса, но имеет доступ к статичным полям и другим статичным методам.

```typescript
class A {
    private static word: string = "Hello";

    public static say() {
        console.log(this.getWord())
    }

    private static getWord(): string {
        return this.word;
    }
}

A.say();
```

## Generic-параметры

Классу можно указывать generic-параметры. Их нужно указывать в `<>` сразу после имени класса. Generic-и выводятся по тем же принципам, что и при вызовах функций.

```typescript
class A<T> {
    public readonly a: T
    constructor(a: T) {
        this.a = a;
    }
}

const a1 = new A(10);
const a2 = new A("lalaka");
const a3 = new A<true>(true);
```

Методы класса могут объявлять собственные generic-и и использовать generic-и объявленные для класса.

```typescript
class A<T> {
    public readonly a: T
    constructor(a: T) {
        this.a = a;
    }

    print<R>(b: R) {
        console.log(this.a, b);
    }
}

const a = new A(10);
a.print("lalaka");
a.print<true>(true);
```

## Наследование

В TypeScript поддерживается возможность наследования классов. Наследование - одна из ключевых механик объектно-ориентированного программирования. При помощи наследования можно передать (унаследовать) поведение одного класса другому классу.

```typescript
class Figure {
    print() {
        console.log("I'm a figure");
    }
}

class Circle extends Figure {
    radius: number = 15;
}

const q1 = new Circle();
q1.radius; // 15
q1.print();
```

В примере выше класс `Figure` содержит метод `print`. Класс `Circle` наследуется (расширяет) класс `Figure`. В этом случаи `Circle` является **наследником** класса `Figure`, а класс `Figure` - **базовом классом** (или **родительским классом**, или **суперклассом (superclass)**) для `Circle`. Все поведение, которое определяется в классе `Figure` (в нашем случаи это метод `print`) передается классу `Circle`. При этом сам класс `Circle` объявляет свое собственное специфичное поведение (поле `radius`) в дополнение к унаследованному. Поэтому инстанс класса `Circle` имеет и поле `radius` и метод `print`.

Если у базового класса объявлен конструктор с обязательными параметрами, то его наследник в своем конструкторе должен вызывать конструктор базового класса. Иначе будет ошибка компиляции.

```typescript
class Rect {
    constructor(public width: number, public height: number) {
    }
}

class Square extends Rect {
    constructor(side: number) {
        super(side, side);
    }
}

const rect = new Rect(15, 10);
const square = new Square(5);
```

Ранее были рассмотрены модификаторы доступа полей и методов. Для того, чтобы сделать какое-то поле или метод доступным только внутри класса или внутри наследников этого класса, используется модификатор `protected`. `private` поля и методы базового класса доступны только внутри самого базового класса и наследникам не передаются.

```typescript
class Rect {
    private width: number;
    private height: number;

    constructor(width: number, height: number) {
        this.width = width;
        this.height = height;
    }

    protected calcArea(): number {
        return this.width*this.height;
    }
}

class Square extends Rect {
    constructor(side: number) {
        super(side, side);
    }

    printArea() {
        const q =  this.width; //Error: Property 'width' is private and only accessible within class 'Rect'.
        console.log(this.calcArea());
    }
}

const square = new Square(5);
square.printArea();
square.calcArea(); //Error: Property 'calcArea' is protected and only accessible within class 'Rect' and its subclasses.
```

Так как наследник расширяет базовый класс - он является надмножеством над базовым классом. С точки зрения типов это означает, что инстансы наследников базового класса могут передаваться туда, где требуется значение с типом базового класса.

```typescript
class Rect {
    constructor(public width: number, public height: number) {
    }
}

class Square extends Rect {
    constructor(side: number) {
        super(side, side);
    }

    onlySquareMethod() {
    }
}

const q1: Square = new Square(10);
const q2: Rect = q1;

q1.onlySquareMethod();
q2.onlySquareMethod(); //Error: Property 'onlySquareMethod' does not exist on type 'Rect'.
```

В коде выше переменная `q2` имеет тип `Rect`, но ей присваивается значение `q1: Square`. Это возможно, потому что тип `Square` имеет все поля типа `Rect`. Однако, не смотря на то, что в `q2` лежит инстанс класса `Square`, поля и методы этого типа использовать нельзя, потому что тип переменной `q2: Rect` и TypeScript в общем случаи не может гарантировать, что в значении этой переменной лежит `Square`.

Наследоваться сразу от двух классов нельзя. TypeScript (как JavaScript) не поддерживает множественное наследование. Можно наследовать один класс от второго, а второй от третьего.

В TypeScript класс может быть абстрактным. Абстрактный класс - это класс, от которого можно наследовать другие классы, но нельзя создавать инстансы этого класса. Абстрактный класс помечается ключевым словом `abstract`.

```typescript
abstract class Figure {
    print() {
        console.log("I'm a figure");
    }
}

class Circle extends Figure {
}

const circle = new Circle();
const figure = new Figure(); //Error: Cannot create an instance of an abstract class.
```

Абстрактные классы могут иметь абстрактные методы. Абстрактные методы - это методы, у которых объявлена сигнатура, но не объявлено тело метода. Абстрактный метод помечается модификатором `abstract`. Наследник абстрактного класса обязан объявить у себя метод с такой же сигнатурой и определить реализацию этого метода. Если наследник не реализует абстрактные методы - будет ошибка компиляции.

```typescript
abstract class A {
    abstract show(p: number): string;
}


//Error: Non-abstract class 'B1' does not implement inherited abstract member 'show' from class 'A'.
class B1 extends A {
}
```

Если наследником класса с абстрактными методами тоже является абстрактный класс, то абстрактные методы реализовывать не обязательно.

```typescript
abstract class A {
    abstract show(p: number): string;
}

abstract class B2 extends A {
}
```

Абстрактные методы стоит воспринимать как интерфейс. Они гарантируют, что независимо от реализации абстрактного класса, они будут реализованы и иметь фиксированную сигнатуру.

```typescript
abstract class BasePrinter {
    abstract print(n: number): void;
}

class ConsolePrinter extends BasePrinter {
    print(n: number): void {
        console.log(n);
    }
}

class DomPrinter extends BasePrinter {
    print(n: number): void {
        const element = document.querySelector("#print");
        if (element != null) {
            element.textContent = n.toString();  
        }
    }
}

const printers: BasePrinter[] = [new ConsolePrinter(), new DomPrinter()];
printers.forEach(p => p.print(10));
```

## Класс, как интерфейс

Инстанс класса - это объект. Как и любой другой объект в TypeScript, он имеет тип. Интерфейсом взаимодействия с инстансом класса из внешнего мира являются его публичные поля и методы. Поэтому, если тип объекта требует наличие каких-либо полей или методов у объекта, и тип класса имеет все эти поля и методы, то инстансы этого класса совместимы с типом объекта.

```typescript
interface A {
    x: number;
}

class B {
    constructor(public x: number) {
    }
}

class C {
    constructor(public x: string) {
    }
}

const a1: A = new B(10);
const a2: A = new C("10"); /* Error:
Type 'C' is not assignable to type 'A'.
  Types of property 'x' are incompatible.
    Type 'string' is not assignable to type 'number'.
*/
```

Тип класса сам может выступать в роли интерфейса.

```typescript
class A {
    public x: number = 15;
}

const a: A = { x: 40 };
```

В коде выше переменная `a` типизирована, как `A`. При этом `A` - это класс. Конструкция `a: A` **не** требует присвоения только инстансов класса `A`. Это конструкция требует любое совместимое с интерфейсом класса значение.

Для более строгой типизации `TypeScript` поддерживает реализацию интерфейса классом. Для этого используется ключевое слово `implements`.

```typescript
interface Figure {
    print: () => void;
}

class Circle implements Figure {
    print() {
        console.log("I'm a circle");
    }
}
```

Если указано, что класс реализует какой-то интерфейс, но в классе (или его базовом классе) не объявлены какие-то поля или методы, указанные в интерфейсе, то TypeScript выдаст ошибку компиляцию

```typescript
interface Figure {
    print: () => void;
}

class Circle implements Figure {
} /* Error:
Class 'Circle' incorrectly implements interface 'Figure'.
  Property 'print' is missing in type 'Circle' but required in type 'Figure'.
*/
```

Класс может реализовывать сразу несколько интерфейсов - их нужно перечислять через запятую после ключевого слова `implements`. Класс может одновременно наследоваться от другого класса и реализовывать множество интерфейсов.

```typescript
interface A {
    a: number;
}

interface B {
    b: string;
}

class X {
    public a: number = 300;
}

class Y extends X implements A, B {
    constructor(public b: string) {
        super();
    }
}
```

Как было сказано ранее, классу `Y` не обязательно реализовывать интерфейсы `A` и `B`, для того, чтобы типы его инстансов были совместимы с этими интерфейсами. Реализация интерфейсов во многом нужна для более строгой типизации и облегчения работы в IDE.

## Объект класса, как тип

Ранее уже говорилось, что объект класса - это своего рода функция, которая конструирует другие объекты (инстансы класса). Так как это объект, соответственно у него есть какой-то тип.

Объект класса можно вызывать как функцию с определенными параметрами, которая вернет определенное значение. Но есть одна важная особенность. Эту функцию-конструктор можно вызывать только с ключевым словом `new`. Поэтому тип объекта класса можно описать при помощи callable со следующей модификацией:

```typescript
interface ClassType {
    new (a: number, b: string): {a: number, b: string, c: boolean}
}
```

Выше был объявлен тип, который описывает множество объектов, которые можно вызывать с оператором `new` и двумя параметрами с заданными типами, и в результате этого вызова вернется объект с заданным интерфейсом.

```typescript
interface ClassType {
    new (a: number, b: string): {a: number, b: string, c: boolean}
}

class A {
    c: boolean = false;
    constructor(public a: number, public b: string) {
    }
}

class B {
    constructor(public a: number, public b: string) {
    }
}

const classType1: ClassType = A;
const classType2: ClassType = B; /* Error:
Type 'typeof B' is not assignable to type 'ClassType'.
  Property 'c' is missing in type 'B' but required in type '{ a: number; b: string; c: boolean; }'.
*/
```

Например, можно объявить тип-помощник, который будет возвращать тип объекта класса.

```typescript
type TypeOf<T> = { new (...args: any[]): T }

class A {
}

class B {
    constructor(public b: string) {
    }
}

const classA: TypeOf<A> = A;
const classB: TypeOf<B> = B;
const wrong: TypeOf<A> = new A(); /* Error:
Type 'A' is not assignable to type 'TypeOf<A>'.
  Type 'A' provides no match for the signature 'new (...args: any[]): A'.
*/
```

## Задания

* [Задание #9](https://www.typescriptlang.org/play?#code/PQKgBAsAUGtouCCAYQQ-CCA4QQEiCsEIghWEDAYwBsBDAZ1LACEyBTaOMQDBBBBEGUD4QQbhBAZEEHYQQYRBAnCC4wgRhBOgLhBUYAESAsEDaAWEFE4eYNpjHjpYKXMVhmajeMSAeEFTaFHQPIgYZIAEQNoCYQHPclgsqND0SAxEFSo9HCA+CBszBx4ToDSIOwcgLwgOHGotuKKiGBOYKlxzJxSCpyAbCBxbKJRWFxggOIgqOGlACwADNAgwNDQoGDySiIqRqiaYK3QRGQUAIJgNAAeAC40AHYAJhTUpDRgAN5BsPgA9gukswBOAK74s3vHABTTAFxgC6cAtgBGNMcAlFs7DGCkpwADh9bgAaGTjaSfADcvwAvu0YHBAadXoQAJb4AjEQj4a4ATweTzeH0+RJe72OPyRfzAxxos1OxwWYFmAAt0aQAHTTMAAajA+NhNLACKgYpGJHIVCmc0WKyotGpDH2hxO50uN0J-xO6IWAHNvtsRQwAcCbgBGRrg-Ew+GIhgotGY7G4gnkklfZW0ukMpkswHEY7rACSC1m13ZnK5tv5guFDDFEqgqqOrvwpxImtIDzWNAA2gBdMAAXjA+YWNAA7mBxtcrZ9wZWa5RrtIrVDC8LU7N-i9S+nM8Rs1znsRAbdSwA+MDTLn4HF4ufTT6fLn0pbnGjXa7EcH4b4lmfEOMH7sHUh7Qg0LmEPb664A552qCdAC0H6GbSgHRAv3kpimIkWCIPYyTmGAAACsykG+MzAhccHHMcVx2GwQFVIkUQGFgjhVJI4KZKkWBsPYUSAKIgYAFBwxTYSI5SVOoAzuJkgAiIKgcSINwJSmGA9g4OgiQBFyvyAKgg4RSJkgCyIJ4lHMLhbD4YglFMYMCSiHwCg4Fg4KpKYaA2CR9hgAAKgAyhkUQKIg8n9CI4h8Fk6EGdY-ioOC7AKI4IgJHgphsMUpQOIp2CIBUYA8FpzBcHcvxsrMsyAjmwDAFWaVcrM+LAqQ+DHOigKzCQBpclc+rAEsez4KQwBssQyyvHsewANbAPS160G+Cx7PM1WZdluX5bMb4AMxvgAnFy8XPIQADEb4wXB0wIUNHwoccb77M8zyLDBLTfr+XT6IYqkmBBwyvsAUELfBNCIatVwjIuQ7ZvmjSFjGwopVdsE3XdyEPVAzaKus9bWjIHYvu+n6tEAA)

* [Задание #10](https://www.typescriptlang.org/play?#code/PQKgBAsAUGtouCCAYQQ-CCA4QQEiCsEIghWEDILhBBuEEUEEQEsADTFTC1WUoBUBPABwFNo4xAMEBOUB8IIUAyIIHYQQMIggThBcYQIwgQ-DQBEgLBABgFhA5OUWAGZ5+JdTCqNYcntSz8iQDwgqI+sKB5EDDJAAiADATCA53i2vSoooiAYiCoqFxwgPggAiSEeF6A0iCChIC8IDipqK74GohgXgQCqSRCNOpCgGwgqQJyiVjCYIDiIKhxNUoATAAMYACMAKxK0CDA0NCgYGqastq6+gL4YMPQAMYANgCGAM6blGAA3tAAvqNQAC5s7EwXYAC8YOsAdswA3CcAlg+n7ABOAGbry0uAEF9pFYAAPABcYAeAFcALYAIx+rygxyg0A+Xz+AMuACFQTA4KxvljoQAKZjQzanUkPADmAEpbgA+MAANwA9m8ACao9HQX6wh7LU5vTkPMDLb7sdZfclQmEI5HfAA0YHOHGhFBYHEZ0JBADIwASDkTYDLTrDvpKHuwAO4ai4Kxn8k7S2Xy-rqiiMgB0JKx5I6nSUjLG4AAtNHFiMMVA1lsdgB5U4ACx+hO4ywlNO+sNFnO+5NYsMRqzeyzAirhSJ+6tL5crYCpSrr32ZZu46IFUFAYImAlstgyWEQ7iy9jAAAFTptI+xwRxRQvvt8i24hzhGhlEuYsJ5Gop1QUclgBO5EoBREDA5UIVT3sjqDUs1hoBUAIiCoVKIETVWxgO4ODoBk4R+gOgCoIHE75gIAsiB0DeJAHgIR6IDer7zGA6RyOI6g4Fg6o5LYaAuOe7hgIwADK+SJOopBYLMVj4OIhTEagLhhKg6qCOoniyOkeC2AIVQ1B4KHYIg9RgKIeEkMIkIDmmpynKwmyQsAwD2lpfqauwmzSm8rCnBsDJ+kW9LADynLLJswBpo8PKIpynIANbADKqyyps7CRg8nJfLZun6aSRmRgAzJGACcfpKfCqwAMSRnOC5LuwK4-Ou3yRjm8LwuwnybEMcYRoOmgWPoNhTksfbADOyWLsupyrplKwynK7Dkt6YCphmHYldGkaxkAA)

* [Тест](https://docs.google.com/forms/d/e/1FAIpQLScGHVFdzcK747iP5ZToxucNWiFQSRcSrmwk6MC_nA9fQA7ZQQ/viewform?usp=sf_link)

* [Пример решения задания #9](https://www.typescriptlang.org/play?#code/PQKgBAsAUGtouCCAYQQ-CCA4QQEiCsEIghWEDAYwBsBDAZ1LACEyBTaOMQDBBBBEGUD4QQbhBAZEEHYQQYRBAnCC4wgRhBOgLhBUYAESAsEDaAWEFE4eYNpjHjpYKXMVhmajeMSAeEFTaFHQPIgYZIAEQNoCYQHPclgsqND0SAxEFSo9HCA+CBszBx4ToDSIOwcgLwgOHGotuKKiGBOYKlxzJxSCpyAbCBxbKJRWFxggOIgqOGlACwADNAgwNDEAEakAC4ATsT43QQk5FS0YADeQbD4APYAdj29AK6Ds70AFAAOyx2EAJb4YAAeAFxg88sAth00vQA0YFu9s900gzQAJmAAnudL+3mAHMAJSTaZgAC+0AhnSWAyG+GIhHwGz+F2ut16IPOlxudwA3NBoVBoKAwPIlCIVEZUJowK1oEQyBQAIJgGjHN7zT4UaikGjgmBwOaLPqrbrrDZnDH47FChgMUjLLZ3aWPaSs6QgonC2AkiE7PaHAjI1HovFYnGyrEKxWwXo0brLXrzMDdAAW+1IADpjmAANS-XUMEkGqDM0aUDlcmg8vnjKZ6ggLJYSqXogHAsFJ+2wZWqzYARkajx+Ooh4YYRoORyRKLRuMxdxzEIYjudrqexF6AoAkvNuhtPd6feXA8HK8SYRHU4izcsSJLe+d+TQANoAXTAAF4wOv5jQAO5gVkbEsgx6Hk+UDbSEvaze60U9MDKq6700oxfEZe+q7EFs0q7gAfCcPr1qixx+iCII+o6nyrDQGwbMQjz4GCO5gcQE4Yc+qazIQNA+oQsxAhs74VlA5IALR0QybSktRIAQvIpimIkWCIPYyTmGAAAC3SkDRnKqoMIm9C8vR2GwHFVIkUQGFgjhVJIjyZKkWBsPYUSAKIgYAFBwxSKSI5SVOodLuJkgAiIKgcSINwJSmGA9g4OgiQBD6EKAKgg4RSJkgCyIJ4+nMMpbCqYg+kWfSCSiHwCg4FgjypKYaA2Fp9hgAAKgAyhkUQKIgoW0iI4h8FkslpdY-ioI87AKI4IgJHgphsMUpQOOF2CIBUYA8AlzBcKcEIet03RbKQpzAMAR6zT63Q-KqpD4L0+xbN0JDAj66xAsAnyzPgpDAB6xA8h0syzAA1sAjpEbQNHzK8NBHQtS0rWt3Q0QAzDRACcPqjVchAAMQ0UJInHGJn13FJNFzFcVxxkJLSMWS4CUgYJUmHxjLUcAAng6J7zQ5J6xMguS7rKQ66NJuY66tNBPCUT4kw2TUDXmMArnqWMgPlRtH0a0QA)

* [Пример решения задания #10](https://www.typescriptlang.org/play?#code/PQKgBAsAUGtouCCAYQQ-CCA4QQEiCsEIghWEDILhBBuEEUEEQEsADTFTC1WUoBUBPABwFNo4xAMEBOUB8IIUAyIIHYQQMIggThBcYQIwgQ-DQBEgLBABgFhA5OUWAGZ5+JdTCqNYcntSz8iQDwgqI+sKB5EDDJAAiADATCA53i2vSoooiAYiCoqFxwgPggAiSEeF6A0iCChIC8IDipqK74GohgXgQCqSRCNOpCgGwgqQJyiVjCYIDiIKhxNUoATAAMYACMAKxK0CDA0NCgYGqastq6+gL4YMPQAMYANgCGAM6blGAAlgC2rKvsB+wAdgAuOwCCADRgAEJgAN6RsMsA9ueblwBOAFdlpdPn8ABSsAEAI1We2WYAAHgAuMDnAEHKHsP4ASle7zAAF9RjA4Kw-nsrmDmCjfuTzgBzXFvEncD7fTafE4AOlWn3pVIelwAFntNlyEdiANz4olQWXQS5sdhMJVgAC8r1R7AA7mDkaj0ZicSibmAAGRPQnSqDQCmXLEAM3Wy2VpuZ3H1aIxWOt8qgdsdzuVz3dpLplxRVJp-wpjPVAD4wAA3T57AAmvuJDoB52Be2+YGWf3Y63tepRXqNgqVKIoLA42JN5stodgxcuAL+5y12rAio4eql0D9RZLZf6Dwo2K5ZLtYI6nSU2LG4AAtOvFiMbVA1lsdgB5YVYvEswvs-5AkHgyEwuGIiuGrEPG+w+HUg3enEn7iyv2gfFqLYtgZFgiDuFk9hgAAAtcq7sAiHDAnBfx-KCbgCMBjQZIk5hYJ4jSKA8BQ5FgAjuIkgCiIGA5SEFUOGyHUDSWNYNAFIAIiCoKkiAiNUthgO4ODoBk4RcvigCoIHErFgIAsiB0FRJB4QIBGIFRzHzGA6RyOI6g4FgDw5LYaAuKR7hgIwADK+SJOopBYLMVj4OIhSGagLhhKgDyCOoniyOkeC2AIVQ1B4SnYIg9RgKIOkkMISL4kKlyXKwmxIsAwDahlXL9uwmxFnsrCXBsDJcqC9LAGmnzLJswBCus5xplCnyfAA1sAxYnFs7Crucnz2tV2W5eSBWrgAzKuACcXIJQcqwAMSrrB8GIZcyGoX8q5fAcZxXJsQxbiuExmBY+g2JBSxQGl0GLQh7BIVia0rMWpbsGCE5gIeQpYsuF1rhuwxAA)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://race-timo.gitbook.io/typescript/classes.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
