Typescript: есть ли способ исключить ошибку при создании интерфейса, если идентичный след уже определен?

#typescript

#typescript

Вопрос:

У нас довольно большой проект Angular / Typescript. Допустим, я определил интерфейс следующим образом

 export interface RangeNumber {
  from: number;
  to: number;
}
  

Я бы хотел, чтобы typescript или linter выдавали ошибку или предупреждение, если кто-то в том же проекте попытается создать интерфейс с точно такими же именами / типами свойств, что и RangeNumber . Например, кто-то создает:

 export interface MyRange {
  from: number;
  to: number;
}
  

В противном случае я должен следить за разработчиками и следить за тем, чтобы они использовали наши общие классы / интерфейсы вместо того, чтобы изобретать колесо. Есть ли способ?

Комментарии:

1. Я не понимаю варианта использования. Почему это имеет значение, если кто-то создает свой собственный интерфейс, структурно идентичный RangeNumber ? И почему вы, вероятно, достаточно беспокоитесь о его запрете? (То есть, как эти разработчики узнают, что им нужен тип, эквивалентный RangeNumber without knowing about RangeNumber ?)

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

3. Основной резонанс заключается в том, что разработчики в целом ленивы обнаруживать существующие типы и, как правило, выбирают путь наименьшего сопротивления, создавая свою собственную версию. Эта проверка заставит их думать не только о своей небольшой части проекта, но и о проекте в целом.

Ответ №1:

Вероятно, вы ищете внешний инструмент статического анализа, а не сам компилятор TypeScript.

Одним из примеров, который приходит на ум, является функция детектора копирования-вставки PMD, которая обеспечивает соблюдение принципа DRY при кодировании: https://pmd.github.io/pmd-6.23.0/pmd_userdocs_cpd.html

Я уверен, что есть и другие подобные инструменты. Однако я не думаю, что какой-либо из них будет близок к идеальному, поскольку обнаружение подобных сходств является сложной задачей, учитывая, насколько это субъективно.

Например, у вас может быть два идентичных интерфейса, но с разными именами, потому что они служат разным целям:

 interface Range {
    from: number;
    to: number;
}

interface Coordinate {
    x: number;
    y: number;
}
  

Что касается типов данных, вы можете поменять местами эти два и заставить код работать точно так же. Но есть смысл сохранить оба из них, одна из причин заключается в том, что это улучшит читаемость кода и поможет разработчику понять, что происходит.

Комментарии:

1. И что гораздо более важно, создание двух интерфейсов, даже если они имеют одинаковые имена / типы свойств, означает, что вы можете добавлять или удалять части одного интерфейса, не затрагивая ни один из других, что означает, что изменения затронут только соответствующие единицы.

2. Если вы должны затем вывести один из другого. Imho интерфейсы копирования / вставки попадают в ту же категорию, что и блоки копирования / вставки кода, вместо того, чтобы извлекать их в повторно используемые функции.

3. @Aziz мой случай касается точной копии имен и типов. В вашем примере я пытаюсь избежать того, чтобы координата имела {from: number; to: number;}

4. @AndreiV Это совсем не то же самое, и это грубое непонимание того, что такое интерфейс и что он делает. Интерфейсы существуют не для уменьшения объема, который вам нужно ввести, они существуют для обеспечения корректности программы. Если вы будете делать то, что говорите, ваш код не будет целостным. Вы используете его как механизм копирования / вставки, который ничем не лучше, чем фактическое копирование / вставка.

5. Например, что, если вы ввели библиотеку, которая использует интерфейс с теми же именами / наборами, что и в вашем собственном коде. Вы бы тоже хотели их проверить? Конечно, нет. Эти интерфейсы имеют отношение только к коду, который его использует. Это то же самое.