Typescript: Статические методы и свойства
Иногда нам требуется задать свойство или метод, который будет общим для всех экземпляров этого класса. Например, чтобы определить, является ли объект экземпляром класса. В таком случае при объявлении метода мы можем указать ключевое слово static, и он станет доступен через имя класса:
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Статическим методам и свойствам также можно назначить модификаторы доступа public, protected и private и модификатор неизменяемости readonly. Это позволяет ограничить использование свойств и методов только текущим классом или наследниками.
Статические свойства и методы наследуются, и подкласс может их переопределить — так же, как в JavaScript:
class CustomFile {
static maxCustomFileSize = 1000;
static isCustomFile(file: CustomFile): boolean {
return file instanceof CustomFile;
}
}
class ImageCustomFile extends CustomFile {
static maxCustomFileSize = 2000;
static isCustomFile(file: CustomFile): boolean {
return file instanceof ImageCustomFile;
}
}
const file = new ImageCustomFile();
console.log(ImageCustomFile.maxCustomFileSize); // 2000
console.log(ImageCustomFile.isCustomFile(file)); // trueЗдесь ImageCustomFile объявил свои maxCustomFileSize и isCustomFile, и обращение по имени подкласса даёт именно их.
TypeScript добавляет к этому одно требование: тип переопределённого свойства или метода должен остаться совместимым с родительским. Если вместо числа подставить строку, код не скомпилируется:
class TextCustomFile extends CustomFile {
static maxCustomFileSize = "unlimited"; // Error!
}Компилятор скажет Class static side 'typeof TextCustomFile' incorrectly extends base class static side 'typeof CustomFile': статическая часть подкласса перестала подходить под статическую часть родителя.
Подкласс, который ничего не переопределяет, пользуется статическими свойствами и методами родителя:
class VideoCustomFile extends CustomFile {}
console.log(VideoCustomFile.maxCustomFileSize); // 1000Задание
Другое полезное применение статических свойств и методов — создание фабричных методов. Фабричный метод — это статический метод, который возвращает новый экземпляр класса. Реализуйте класс UserResponse с полем user: string и фабричный метод fromArray, который принимает массив и возвращает массив экземпляров класса UserResponse:
const response = UserResponse.fromArray(["user1", "user2", "user3"]);
console.log(response[0].user); // user1
console.log(response[0] instanceof UserResponse); // trueTypescript: Статические методы и свойства
Иногда нам требуется задать свойство или метод, который будет общим для всех экземпляров этого класса. Например, чтобы определить, является ли объект экземпляром класса. В таком случае при объявлении метода мы можем указать ключевое слово static, и он станет доступен через имя класса:
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Статическим методам и свойствам также можно назначить модификаторы доступа public, protected и private и модификатор неизменяемости readonly. Это позволяет ограничить использование свойств и методов только текущим классом или наследниками.
Статические свойства и методы наследуются, и подкласс может их переопределить — так же, как в JavaScript:
class CustomFile {
static maxCustomFileSize = 1000;
static isCustomFile(file: CustomFile): boolean {
return file instanceof CustomFile;
}
}
class ImageCustomFile extends CustomFile {
static maxCustomFileSize = 2000;
static isCustomFile(file: CustomFile): boolean {
return file instanceof ImageCustomFile;
}
}
const file = new ImageCustomFile();
console.log(ImageCustomFile.maxCustomFileSize); // 2000
console.log(ImageCustomFile.isCustomFile(file)); // trueЗдесь ImageCustomFile объявил свои maxCustomFileSize и isCustomFile, и обращение по имени подкласса даёт именно их.
TypeScript добавляет к этому одно требование: тип переопределённого свойства или метода должен остаться совместимым с родительским. Если вместо числа подставить строку, код не скомпилируется:
class TextCustomFile extends CustomFile {
static maxCustomFileSize = "unlimited"; // Error!
}Компилятор скажет Class static side 'typeof TextCustomFile' incorrectly extends base class static side 'typeof CustomFile': статическая часть подкласса перестала подходить под статическую часть родителя.
Подкласс, который ничего не переопределяет, пользуется статическими свойствами и методами родителя:
class VideoCustomFile extends CustomFile {}
console.log(VideoCustomFile.maxCustomFileSize); // 1000Задание
Другое полезное применение статических свойств и методов — создание фабричных методов. Фабричный метод — это статический метод, который возвращает новый экземпляр класса. Реализуйте класс UserResponse с полем user: string и фабричный метод fromArray, который принимает массив и возвращает массив экземпляров класса UserResponse:
const response = UserResponse.fromArray(["user1", "user2", "user3"]);
console.log(response[0].user); // user1
console.log(response[0] instanceof UserResponse); // trueВаше упражнение проверяется по этим тестам
import { expect, test } from "vitest";
import UserResponse from "./index";
test("UserResponse", () => {
const users = ["user1", "user2"];
const result = UserResponse.fromArray(users);
expect(result).toEqual([new UserResponse("user1"), new UserResponse("user2")]);
expect(result[0]).toBeInstanceOf(UserResponse);
const users2 = ["user3", "user4", "user5"];
const result2 = UserResponse.fromArray(users2);
expect(result2[0].user).toBe("user3");
expect(result2[2]).toBeInstanceOf(UserResponse);
});Решение учителя откроется через:
20:00
