«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Освоение TypeScript: понимание возможностей расширений

Освоение TypeScript: понимание возможностей расширений

Опубликовано 6 ноября 2024 г.
Просматривать:266

Mastering TypeScript: Understanding the Power of extends

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

Наследование с использованием расширений

Одним из основных применений расширений является наследование, позволяющее создавать новые интерфейсы или классы, основанные на существующих.

interface User {
  firstName: string;
  lastName: string;
  email: string;
}

interface StaffUser extends User {
  roles: string[];
  department: string;
}

const regularUser: User = {
  firstName: "John",
  lastName: "Doe",
  email: "[email protected]"
};

const staffMember: StaffUser = {
  firstName: "Jane",
  lastName: "Smith",
  email: "[email protected]",
  roles: ["Manager", "Developer"],
  department: "Engineering"
};

В этом примере StaffUser расширяет User, наследуя все его свойства и добавляя новые. Это позволяет нам создавать более конкретные типы на основе более общих.

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

Ключевое слово расширяется также используется для наследования классов:

class Animal {
  constructor(public name: string) {}

  makeSound(): void {
    console.log("Some generic animal sound");
  }
}

class Dog extends Animal {
  constructor(name: string, public breed: string) {
    super(name);
  }

  makeSound(): void {
    console.log("Woof! Woof!");
  }

  fetch(): void {
    console.log(`${this.name} is fetching the ball!`);
  }
}

const myDog = new Dog("Buddy", "Golden Retriever");
myDog.makeSound(); // Output: Woof! Woof!
myDog.fetch(); // Output: Buddy is fetching the ball!

Здесь Dog расширяет Animal, наследуя его свойства и методы, а также добавляя свои собственные.

Ограничения типов в дженериках

Ключевое слово Extensions имеет решающее значение при работе с универсальными шаблонами, позволяя нам ограничить типы, которые можно использовать с универсальной функцией или классом.

interface Printable {
  print(): void;
}

function printObject(obj: T) {
  obj.print();
}

class Book implements Printable {
  print() {
    console.log("Printing a book.");
  }
}

class Magazine implements Printable {
  print() {
    console.log("Printing a magazine.");
  }
}

const myBook = new Book();
const myMagazine = new Magazine();

printObject(myBook);      // Output: Printing a book.
printObject(myMagazine);  // Output: Printing a magazine.
// printObject(42);       // Error, number doesn't have a 'print' method
  1. Интерфейс Printable: Здесь мы определяем интерфейс с именем Printable. Этот интерфейс объявляет контракт, которого должен придерживаться любой реализующий его класс. Контракт определяет, что любой класс, реализующий Printable, должен предоставлять метод с именем print, который не принимает аргументов и возвращает void.
  2. функция printObject(obj: T): это универсальная функция с именем printObject. Он принимает один аргумент с именем obj, который имеет тип T. Параметр типа T ограничен типами, которые расширяют (реализуют) интерфейс Printable и могут использоваться в качестве аргумента этой функции.
  3. Класс Book реализует Printable, а класс Magazine реализует Printable. Здесь мы определяем два класса, Book и Magazine, оба из которых реализуют интерфейс Printable. Это означает, что эти классы должны предоставлять метод печати, как того требует контракт интерфейса Printable.
  4. const myBook = новая книга(); и const myMagazine = new Magazine();: мы создаем экземпляры классов Book и Magazine.
  5. printObject(мояКнига); и printObject(myMagazine);: Мы вызываем функцию printObject с экземплярами Book и Magazine. Поскольку классы Book и Magazine реализуют интерфейс Printable, они удовлетворяют ограничению параметра типа T Extensions Printable. Внутри функции вызывается метод печати соответствующего класса, что приводит к ожидаемому результату.
  6. // printObject(42);: Если мы попытаемся вызвать printObject с типом, который не реализует интерфейс Printable, например с номером 42, TypeScript выдаст ошибку. Это связано с тем, что ограничение типа не удовлетворено, поскольку число не имеет метода печати, как того требует интерфейс Printable.

Подводя итог, ключевое слово Extensions в контексте функции printObject(obj: T) используется для обеспечения того, чтобы тип T, используемый в качестве аргумента, соответствовал контракту, определенному интерфейсом Printable. Это гарантирует, что с функцией printObject можно использовать только типы с методом print, обеспечивая определенное поведение и контракт на использование функции.

Условные типы

T extends U ? X : Y
  • T — тип, который проверяется
  • U — тип условия, по которому проверяется T.
  • X — это тип, к которому оценивается условный тип, если T расширяется (назначается) U
  • Y — это тип, к которому оценивается условный тип, если T не расширяет U
type ExtractNumber = T extends number ? T : never;

type NumberOrNever = ExtractNumber; // number
type StringOrNever = ExtractNumber; // never

Здесь тип ExtractNumber принимает параметр типа T. Условный тип проверяет, расширяет ли T числовой тип. если да, то тип разрешается в T (который является числовым типом). Если это не так, тип разрешается как никогда.

Ключевое слово расширяет типы объединений

Теперь давайте рассмотрим выражение A | Б | C расширяет A. На первый взгляд это может показаться нелогичным, но в TypeScript это условие на самом деле неверно. И вот почему:

  1. В TypeScript использование расширений с типом объединения слева эквивалентно вопросу: "Каждый ли возможный тип в этом объединении может быть присвоен типу справа?"
  2. Другими словами, A | Б | C расширяет A спрашивает: "Может ли A быть назначено A, И может ли B быть назначено A, И может ли C быть назначено A?"
  3. Хотя A, безусловно, может быть присвоено A, B и C могут быть не присвоены A (если только они не являются подтипами A), поэтому общий результат является ложным.
type Fruit = "apple" | "banana" | "cherry";
type CitrusFruit = "lemon" | "orange";

type IsCitrus = T extends CitrusFruit ? true : false;

type Test1 = IsCitrus; // true
type Test2 = IsCitrus; // false
type Test3 = IsCitrus; // false

В этом примере IsCitrus имеет значение false, поскольку не все фрукты в объединении Fruit являются CitrusFruit.

Лучшие практики и советы

  • Используйте расширения для значимых отношений.: используйте наследование только тогда, когда между типами существует четкая связь "is-a".
  • Предпочитайте композицию наследованию: во многих случаях композиция (с использованием интерфейсов и пересечений типов) может быть более гибкой, чем наследование классов.
  • Будьте осторожны с глубокими цепочками наследования: глубокое наследование может затруднить понимание и поддержку кода.
  • Используйте условные типы для гибких API.: используйте условные типы с расширениями для создания API, которые адаптируются в зависимости от типов ввода.
  • Используйте расширения в дженериках для создания многоразовых, типобезопасных функций.: это позволяет вам писать функции, которые работают с различными типами, сохраняя при этом безопасность типов.
Заявление о выпуске Эта статья воспроизведена по адресу: https://dev.to/hasanm95/mastering-typescript-understanding-the-power-of-extends-1n2o?1. Если есть какие-либо нарушения, свяжитесь с [email protected], чтобы удалить их.
Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3