эквивалент typedef для Typescript - PullRequest
1 голос
/ 18 апреля 2020

У меня есть различные типы целочисленных идентификаторов в моем приложении (например, ProductId, UserId и т. Д. c.), Которые я хочу реализовать строгой типизацией, чтобы быть уверенным, что я передаю правильный тип идентификатора методам.

например, я хочу объявить GetProduct(productId: ProductId) вместо GetProduct(productId: number) так, чтобы ему могли быть переданы только переменные с типом ProductId.

В мои C дней я бы использовал typedef - например, typedef ProductId int;

В C# я достиг этого, определив класс ProductId с неявным приведением к оператору int и явным приведением к оператору int. Более громоздкий, чем typedef, но он работает.

Я пытаюсь выяснить, как сделать эквивалент в Typescript. Для TypeScript я попробовал это:

export class ProductId extends Number {}

, но это все же позволяет передавать число вместо ProductId.

Как можно выполнить sh это в TypeScript?

Ответы [ 2 ]

6 голосов
/ 19 апреля 2020

Это можно сделать, приложив некоторые усилия.

Хитрость заключается в том, чтобы определить ваше ProductID как нечто, находящееся в TS, отличное от номера, но все же число, когда на самом деле работает как Javascript .

Я написал об этом в своем блоге здесь: https://evertpot.com/opaque-ts-types/

Но я поделюсь важными деталями здесь:

declare const validProductId: unique symbol;

type ProductId = number & {
  [validProductId]: true
}

Примечание что даже если мы объявили «уникальный символ», он полностью удален из Javascript, так что на самом деле ProductId символ * добавлен к вашему *1016*, что было бы больно.

Чтобы на самом деле получить что-то, распознаваемое как ProductId, вам нужно написать либо функцию подтверждения, либо функцию защиты типа, либо просто приведение из того места, где ProductId фактически разрешено генерировать.

И, повторюсь, нет необходимости добавлять этот символ к вашему ProductId, это просто , чтобы убедиться, что Typescript распознает ProductId как отличный от number тип. Во время выполнения это просто number.

Это шаблон great для вашего варианта использования. По сути, это показатель того, что это не просто число, а число, проверенное вашей бизнес-логикой c как идентификатор продукта.

1 голос
/ 19 апреля 2020

Вы не можете сделать это в TypeScript.

Использование псевдонимов не препятствует передаче значений другого типа. Если вы объявляете тип B как псевдоним типа A , во всех местах, где ожидается тип B , вы можете также передавать параметры типа A и наоборот.

Как насчет инкапсуляции одного типа в другой? Предположим, что типы A и B имеют по одному члену типа number . Поможет ли такая обертка? Нет. Совместимость классов и интерфейсов в TypeScript определяется на основе их структуры. Если два разных типа имеют идентичную структуру, они совместимы. Можно использовать одно вместо другого.

...