Как справиться с конфликтами имен типов в файле определения машинописного текста

Я пытаюсь написать файл определения машинописного текста для уже существующей библиотеки. Эта библиотека (react-filepond) экспортирует объект с именем File (как видно из < href="https://github.com/pqina/react-filepond" rel="nofollow noreferrer">пример использования в файле README).

Проблема в том, что другой интерфейс, который создает эта библиотека, использует Интерфейс файлов JS.

Итак, теперь в моем файле определения машинописного текста мне нужно каким-то образом управлять двумя определениями типа File. Мое решение состояло в том, чтобы объявить объект, который создает библиотека, как другое имя в моем файле определения и просто экспортировать его как файл.

declare class FilePondFile extends React.Component<FilePondFileProps> { }
export { FilePondFile as File };

Это кажется прекрасным и стильным, когда я использую этот шрифт в своем собственном проекте. Но как сторонник OSS, я хочу сделать это определение доступным для сообщества через репозиторий Definitely Typed. .

Их линтер выдает мне ошибку, хотя это, по-видимому, препятствует просмотру моего PR:

Error: C:/dev/DefinitelyTyped/types/react-filepond/index.d.ts:22:1
ERROR: 22:1   strict-export-declare-modifiers  'declare' keyword is redundant here. 
See: https://github.com/Microsoft/dtslint/blob/master/docs/strict-export-declare-modifiers.md

На первый взгляд кажется достаточно простым удалить declare перед class FilePondFile, однако, если я его удалю, я получаю другую ошибку:

A 'declare' modifier is required for a top level declaration in a .d.ts file. 

Поэтому я не уверен, как справиться с этим противоречием. У сопровождающих Definitely Typed, похоже, нет времени на помощь, поскольку мой PR был только что помечен как «Требуется внимание автора», несмотря на то, что я четко изложил эту проблему.

Есть ли у кого-нибудь предложение, что я могу сделать, чтобы не дублировать ссылку на File в этом файле определения, а также передать линтер с определенным типом?


person Zach Posten    schedule 20.12.2018    source источник
comment
То, чего вы пытаетесь достичь, кажется невозможным с текущими правилами dtslint, вы можете попытаться зарегистрировать проблему в dtslint repo< /а>   -  person artem    schedule 21.12.2018


Ответы (2)


Проблема в том, что другой интерфейс, создаваемый этой библиотекой, использует интерфейс JS File.

Есть другое решение.

Имя File берется классом, объявленным и экспортированным из этого модуля.

Вы должны описать FilePondItem интерфейс в том же модуле, и он должен иметь file свойство с File типом, который отличается - он должен ссылаться на глобальный File объект, который определен в lib.dom.d.ts

export interface FilePondItem {
    file: File;

Типы TypeScript являются структурными. Вам не нужно ссылаться на глобальный File тип по имени, вы можете указать его определение, совместимое с определением в lib.dom.d.ts:

export interface FilePondItem {
    file: Blob & {readonly lastModified: number; readonly name: string};

и все будет хорошо, пока определения типов останутся совместимыми.

Есть, конечно, и минусы: это дублирующийся код, он более многословен, и есть риск, что он станет несовместимым с реальным File в будущем при изменении глобального типа File (однако я думаю, что это маловероятно).

person artem    schedule 21.12.2018
comment
Это отличная идея, спасибо! К сожалению, после объявления исходного ответа Кароля, устранившего ошибки линтинга, мой запрос на извлечение был объединен всего за несколько минут до того, как вы опубликовали этот ответ. В ближайшее время сделаю модификацию. - person Zach Posten; 21.12.2018

Это сообщение об ошибке:

Модификатор 'declare' требуется для объявления верхнего уровня в файле .d.ts.

отображается, когда файл декларации ничего не экспортирует. Ключевое слово declare является избыточным, поскольку оно уже предполагается в *.d.ts файлах.

Цель создания файлов объявлений — точно описать, что происходит в соответствующем модуле JavaScript. На момент написания этого сообщения react-filepond содержит 3 именованных экспорта: const registerPlugin, class FilePond и class File. Это означает, что ваше объявление может выглядеть так:

types/react-filepond/index.d.ts

import * as React from 'react';
import { registerPlugin } from 'filepond';

export { registerPlugin };

interface Props { /* FilePond props here */ }

export class FilePond extends React.Component<Props> { }

export class File extends React.Component { }

потому что это то, что действительно происходит в модуле. Примечание: если типов для filepond нет, может быть хорошей идеей начать с создания типов для этой библиотеки.

Если потребитель сталкивается с конфликтами имен, его роль заключается в локальном предоставлении псевдонима:

import { File as FileComponent } from 'react-filepond';

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

person Karol Majewski    schedule 21.12.2018
comment
Но это вводит в заблуждение, потому что эта библиотека javascript не экспортирует ничего с именем FilePondFile — любой, кто попытается использовать это имя, получит ReferenceError: Cannot find variable: FilePondFile во время выполнения. - person artem; 21.12.2018
comment
Вы правы, это упущение. Я обновил ответ. - person Karol Majewski; 21.12.2018
comment
KarolMajewski Я был готов отметить ваш первоначальный ответ как правильный, но я считаю, что ваш обновленный ответ больше не решает проблему предотвращения конфликта имен. У @artem есть очень веская точка зрения, что экспорт обоих вводит в заблуждение, но на данный момент я считаю, что иметь немного вводящее в заблуждение определение типа предпочтительнее, чем вообще не иметь его. Если вы восстановите свой первоначальный ответ, я отмечу его повторно! - person Zach Posten; 21.12.2018
comment
Спасибо, но это было бы несправедливо — цель файлов объявлений — точно описать, что происходит в соответствующем модуле JavaScript. В этом случае модуль имеет 3 именованных экспорта: const registerPlugin, class FilePond и class File. Поскольку они являются именованными экспортами, вам необходимо сохранить их имена, иначе потребители библиотек могут столкнуться с проблемами. В случае возникновения конфликта роль потребителя состоит в том, чтобы предоставить псевдоним, чтобы предотвратить его (import { File as FileComponent } from 'react-filepond';). - person Karol Majewski; 21.12.2018