Для меня это лучший результат в Google, поэтому я считаю, что должен предоставить найденные мной решения.
С помощью bigint
Теперь bigint, когда наступил 2020 год, и он был принят, он заслуживает упоминания. Вы можете просто сделать следующее. Остерегайтесь того, что bigintони имеют большее влияние на производительность по сравнению с number.
const myNumber: bigint = 10n
Использование номинального типа / маркированного типа / непрозрачного типа
Альтернативой является использование номинального типа, но он, возможно, менее эргономичен, и я не уверен, что он быстрее bigint, но шаблон действительно распространяется на любой тип, а не только number. TypeScript не имеет «первоклассной» поддержки для этого, поэтому вам придется пойти на хитрость. Для этого есть библиотека, newtype-tsкоторая включает общие типы, например, Integerвы можете просто использовать ее, но я объясню работу ниже.
Для начала определим integerтип.
const TAG = Symbol()
type integer = number & { readonly [TAG]: unique symbol }
Это TAGгарантирует, что у нас есть уникальное значение, чтобы мы случайно не создали объект с тем же ключом, и мы также делаем поле уникальным символом по той же причине. Теперь у вашего целого числа на самом деле не будет этого поля объекта, но это нормально.
С этим вы все еще можете добавить integerк numberusing +. Фигово. Таким образом, вы можете обеспечить безопасность типов для аргументов здесь, массируя систему типов с помощью функции. Я просто назову это охранником, и опять же, как вы можете видеть, это не относится к integers - вы можете создать более непрозрачные типы и использовать это снова.
type guard = <A>(f: (...ns: Array<A>) => A, ...ns: Array<A>) => A
const guard: guard = (f, ...ns) => f(...ns)
Если вы попытаетесь вызвать это с помощью number
const bad: integer = guard((a, b) => a + b as integer, myCoolInteger, 10)
вы получите ошибку, как показано ниже
Argument of type '10' is not assignable to parameter of type 'integer'.
Type '10' is not assignable to type '{ readonly [TAG]: unique symbol; }'.(2345)
Обратите внимание, что вы не применяете здесь возвращаемый тип (потому что вы должны использовать as integer), и некоторые операторы, например, /будут возвращать числа с плавающей запятой, поэтому вы, вероятно, все равно захотите выполнять проверки времени выполнения или добавлять Math.roundв специализированную версию guard, но это, по крайней мере, убедитесь, что вы не пытаетесь использовать два отдельных числовых типа вместе - представьте, что у вас есть GBPи, USDи попробуйте добавить те, которые, вероятно, не будут такими, как вы планировали.