Что означает «может рассматриваться как тип интерфейса» в руководстве по TypeScript?

В справочнике написано, что:

Важно понимать, что предложение implements — это всего лишь проверка того, что класс можно рассматривать как тип интерфейса. Это вообще не меняет тип класса или его методы. Распространенным источником ошибки является предположение, что предложение реализации изменит тип класса — это не так!

Но я не понимаю, что означает «может рассматриваться как тип интерфейса», когда там также говорится: «Это вообще не меняет тип класса или его методы».

Означает ли это, что мне нужно повторять одни и те же типы как для класса, так и для интерфейса?

Они приводят пример, где тип s равен any:

interface Checkable {
  check(name: string): boolean;
}
 
class NameChecker implements Checkable {
  check(s) {
    // Notice no error here
    return s.toLowerCase() === "ok";
  }
}

Это просто проверка, а не контекстный тип. Да, вам нужно полностью аннотировать все в классе. Добавление предложения implements может вызвать только ошибку. Все, что он делает, — это проверяет, можно ли назначить тип экземпляра класса реализуемому интерфейсу.

jcalz 21.04.2024 15:43

@jcalz Итак, implements нужно гарантировать, что его можно назначить типу interface?

NeoZoom.lua 21.04.2024 15:46
class X implements Y {} проверяет, что экземпляры X можно назначить Y. Y обычно является интерфейсом, но это не обязательно
jcalz 21.04.2024 16:49
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
3
76
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

«Рассматриваться как тип интерфейса» означает, что везде, где реализованный интерфейс Checkable требуется или ожидается в базе кода, экземпляр реализации NameChecker будет полностью удовлетворять этому условию.

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

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

Ключевое слово implements в Typescript обеспечивает структурное подтипирование. [1]

A class может implement и interface, и экземпляры этого class можно рассматривать как экземпляры interface, что позволяет создавать структурные подтипы.

Но я не понимаю, что означает «может рассматриваться как тип интерфейса», когда там также говорится: «Это вообще не меняет тип класса или его методы».

Он не меняет тип class или его методы в отличие от наследования — Children теперь становится подтипом Parent, а наследуемые методы Parent теперь существуют в Children.

Все, что он делает, это гарантирует, что экземпляр class можно рассматривать как экземпляр interface, если он выполнил все, что указано в контракте, то есть полностью implements обязательные поля interface.


В приведенном мной примере код check(s) { ... } пропускает все типы, но все равно (в ваших терминах) выполняет контракт. [2]

Для ясности позвольте мне объяснить, что спрашивает ОП.

Рассмотрим interface:

interface Checkable {
  check(S: Type): boolean;
}

Следующие классы implementinterface следующие:

class NameChecker implements Checkable {
  check(name: string): boolean
  {
    return name.toLowerCase() === "john doe";
  }
}

class AgeChecker implements Checkable {
  check(age: number): boolean
  {
    return age === 50;
  }
}

Почему приведенное выше считается «полной реализацией» по ключевому слову implements даже с явно разными сигнатурами методов?

Это связано с тем, что Typescript использует структурную типизацию для определения совместимости типов. Для функций это означает, что вам не обязательно иметь одну и ту же подпись для объявления и реализации, если компилятор может определить реализацию, которую можно безопасно вызывать через объявление. Все, о чем вам нужно беспокоиться, — это параметры функции и дисперсия.


[1] Typescript already makes use of structural subtyping. All implements does is that it provides a strict check hence the use of "ensures" in the above wording.

[2] Actually it doesn’t omit every type, the type becomes any implicitly.

Когда я спросил: «Означает ли это, что мне нужно повторять одни и те же типы как для класса, так и для интерфейса?», в моей голове прозвучал голос, говорящий, что нет. В приведенном мной примере код check(s) { ... } пропускает все типы, но все равно (в ваших терминах) выполняет контракт. Почему? А слово «исполнить» — с моей точки зрения, очень расплывчатый термин: оно в данном случае ничего не объясняет.

NeoZoom.lua 22.04.2024 09:01

Вам не обязательно иметь в интерфейсе только реализацию сигнатуры метода. Вы можете перегружаться. Главное, чтобы контракт был выполнен. В этом примере check перегружен параметром s, который неявно имеет тип any. Когда значение имеет тип any, вы можете получить доступ к любым его свойствам (которые, в свою очередь, будут иметь тип any), вызвать его как функцию, присвоить его (или из) значению типа any или что-нибудь еще. это синтаксически законно. Это не приведет к ошибкам проверки типов, поэтому есть комментарий «Здесь нет ошибок».

Chukwujiobi Canon 22.04.2024 12:09

Typescript использует структурную типизацию для определения совместимости типов. Для функций это означает, что вам не обязательно иметь одну и ту же подпись для объявления и реализации, если компилятор может определить, что реализацию можно безопасно вызывать через объявление. Все, о чем вам нужно беспокоиться, — это параметры функции и дисперсия.

Chukwujiobi Canon 22.04.2024 12:19

Вы уверены, что здесь дело в перегрузке функций?

NeoZoom.lua 22.04.2024 15:30

Вам не обязательно иметь одну и ту же подпись для объявления и реализации, если компилятор может определить, что реализацию можно безопасно вызывать через объявление. Все, о чем вам нужно беспокоиться, — это параметры функции и дисперсия. Если хотите, можете перегрузить. У вас не может быть методов, совпадающих с подписью interface. Важно то, что правильный метод существует.

Chukwujiobi Canon 22.04.2024 16:26
Ответ принят как подходящий

Пункт 1: Может рассматриваться как тип интерфейса:

Предположим, вы создаете интерфейс, и два разных класса реализуют его, как показано ниже:

interface Alphabet {
  x: number;
  y?: number;
}
class C implements Alphabet { //Error
  z = 0; 
}
class D implements Alphabet { 
  x= 1; 
  y = 0;
}

c выдает ошибку, поскольку c нельзя рассматривать как что-то типа Alphabet. Ключевое слово implements предназначено для этой проверки и выдает ошибку.

Детская площадка

Предложение 2: вообще не меняет тип класса или его методы:

В приведенном ниже примере можно (ошибочно) ожидать, что c.y будет действительным, хотя undefined. Но это не тот случай. Т. к. тип c по-прежнему C, это не Alphabet.

interface Alphabet {
  x: number;
  y?: number;
}
class C implements Alphabet {
  x = 0;
}
class D implements Alphabet {
  x= 1;
  y = 0;
}
const c = new C();
const d = new D();

c.y; //Error
d.y; //No Error

Детская площадка

И это путаница, против которой предупреждает руководство.

Важно отметить, что удаление implements Alphabet ничего не меняет в остальном коде. Вы по-прежнему можете использовать экземпляры C и D, где ожидается Alphabet.

jcalz 21.04.2024 18:55

О, да. Как вы упомянули в комментарии, это предложение может вызвать только ошибку. Тогда я предполагаю, что утверждение *. Поскольку оба класса D и C успешно реализовали алфавит*`, он недействителен.

Tushar Shahi 21.04.2024 19:49

У меня вопрос: "может рассматриваться как тип интерфейса" Это предсказуемо, т.е. действительно ли мне нужен компилятор, чтобы сообщить мне, что есть ошибка? Похоже, что каждое свойство и метод должны быть подтипом. В моем случае s относится к типу any, то есть это подтип string?

NeoZoom.lua 22.04.2024 08:46
Do I really need a compiler to tell me that there is an error? -> Да, верно. Огромные проекты, где интерфейс может находиться в одном месте, а класс в другом. Я думаю, вы не можете постоянно проверять каждое поле, чтобы проверить, правильно ли вы его реализовали в классе или нет. В этом вся суть TypeScript.
Tushar Shahi 23.04.2024 13:13
any не является подтипом string. any — это ваш выход из TypeScript. Используя any, вы можете избежать проверки типа.
Tushar Shahi 23.04.2024 13:18

Другие вопросы по теме

Похожие вопросы

Angular 17: Почему этот код отображается неправильно?
Использование pdfjs в Sveltekit/Typescript
Как отобразить карусель видео YouTube в этом приложении фильмов Angular 16?
Тип — работа. Но при этом теряется подсказка для правильного варианта... Почему? или Как улучшить?
Net::ERR_CONNECTION_REFUSED и неперехваченная ошибка при использовании Axios с использованием TanStack-Query useMutation (asyncMutation)
Как отключить проверку сборки angular cling в определенном каталоге?
Использование сокращения() изменяет исходный массив в документации JavaScript, утверждающей обратное
Реализация перехода от бегущей линии вперед (CLA) к шаблону поиска области задач в Leaflet.js
Как отобразить изображение по умолчанию, только если в этом приложении фильмов Angular 16 нет постера фильма?
Внедрение зависимостей NestJs в конструктор не определено для поставщика на основе классов, но работает с поставщиком токенов