Как применить интерфейс к классу в typescript?

Есть интерфейс:

interface Helpers {
  props: HelpersProps;
  appConstants: AppConstants;

  log(data: string[]): boolean;
}

Есть класс:

class Helpers implements Helpers {
  constructor(props) {
    const { appConstants } = props;

    this.appConstants = appConstants;
  }

  log(...data) {
    ... Тут код.

    return true;
  }
}

Вопрос:

1)Почему props и ...data имеют тип any? Implements влияет?

Я понимаю, что можно задать типы "по месту" (log(...data: string[]) {), но для чего тогда интерфейс?


Ответы (1 шт):

Автор решения: Alexander Lonberg

Представленный код абсолютно бесполезен(за некоторым исключением). TypeScript очень своеобразно обрабатывает ссылки на типы, ... и, по большому счету, для него не важно type|interface|class.

Попробуйте изменить имя интерфейса на IHelpers, и сразу увидите ошибку неверной реализации. Попробуйте изменить ключевое слово interface на type, ...Ой, он вдруг стал интерфейсом.

Одноименные интерфейсы и классы сообщают компилятору о смешивании типа:

// Декларируем одноименный интерфейс
interface Helpers {
  print(): void
}

class Helpers {
  log(): void {
    // ...
  }
}

const h = new Helpers()
h.log()
// Удивительное дело, метод не реализован, но присутствует в типе.
// TypeScript, при этом, не воспринимает это ошибкой.
h.print()

Playground

Резюмируя можно сказать:
Одноименными интерфейсами мы сообщаем о наличии тех или иных свойств типа, которые могут быть реализованы не в нашем коде, а сторонним движком/приложением. Собственно в файлах lib.*.d.ts и описаны интерфейсы стандартных типов JS.

PS: Кроме того, подобное поведение позволяет легко расширять библиотеку типов, когда файл lib.2015.d.ts расширяется lib.2021.d.ts.

PPS: ... а нам это может понадобится, для добавления кастомных свойств стандартным типам.

→ Ссылка