TypeScript - Как проверить, реализует ли объект интерфейс во время компиляции? - PullRequest
1 голос
/ 07 мая 2019

Вопрос

Допустим, у меня есть два файла - файл интерфейса (например, файл заголовка в C) и файл реализации.

intf.ts (файл интерфейса):

export default interface
{
  foo(baz: number): boolean
  bar(baz: number): string
};

impl.ts (файл реализации):

export default
{
  foo(baz: number): boolean
  {
    return baz > 0;
  }

  bar(baz: number): string
  {
    return baz > 0 ? "john" : "doe"
  }
};

Как определить, реализует ли экспорт по умолчанию impl.ts экспорт по умолчанию intf.ts?Предположим, что я не могу изменить ни один из этих файлов.

Что-то вроде:

import intf from `./intf.ts`;
import impl from `./impl.ts`;

if (impl implements intf)
  console.log("Good input!");
else
  console.log("Bad input! Input does not implement interface!");

Примечание: ответ не должен быть определенвнутри сценария машинописи.


Мое частично рабочее решение

Вот решение, которое я придумала, которое частично работает:

check_if_implements.ts

import intf from `./intf.ts`;
import impl from `./impl.ts`;

function check(_: intf) {};
check(impl);

Этот скрипт создаст ошибку во время компиляции, если реализация не реализует интерфейс.

Затем я могу скомпилировать этот скрипт и проверить, есть ли ошибка, чтобы определить ответ.

С этим связана одна проблема: как отличить (в коде) ошибку «не реализует» от любой другой ошибки?


Почему я это делаю?

Я пытаюсь изучить чистую архитектуру, и TypeScript хорошо работает с чистой архитектурой из-за статической проверки типов.Например, внедрение зависимостей легко сделать в TypeScript.

Мой план состоит в том, чтобы каждый «модуль» (сущность, сценарий использования, реализация интерфейса и т. Д.) Имел файл «интерфейс» и «реализация» (например,в вопросе).

Когда модули зависят от других модулей, а не от имени и версии (например, "package_name": "^1.0.2" в npm), модуль зависит от определенного интерфейса.Модуль может скопировать интерфейс из существующего модуля или создать свой собственный.

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

Так что теперь мне нужно определить, реализует ли реализация с статической инъекцией интерфейс.


Спасибо за любой вклад!

1 Ответ

2 голосов
/ 07 мая 2019

Вы можете проверить это полностью в системе типов. Вы можете использовать import('module'), чтобы получить тип модуля и сформировать там, вы можете создать тип, который выдаст ошибку, если реализация неверна:

type Check<T extends import('./intf').default> = T;
type IsOk = Check<typeof import('./impl')['default']>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...