javascript - typescript 参数中允许的最小数量
问题描述
我有一个类似的功能:
function getBlogs(limit?: number) { ... }
limit
只能是正整数,不能是0
。
我如何告诉打字稿这个数字只能大于 0?
解决方案
有一个开放的建议microsoft/TypeScript#15480来支持“范围类型”,您可以在其中说诸如 type PositiveWholeNumbers = 1..9999999
表示您的类型之类的东西。还有一个(关闭的)建议microsoft/TypeScript#4639来支持int
和uint
-like 类型,它也可能在这里工作。遗憾的是,这些都没有实现,所以如果你想在类型系统中实现这一点,你需要做其他事情。
如果有一个相当小的上限(最多数千个),您可以手动生成允许值的并集并将其推送到某个库文件中。这可以通过编程方式完成,因此您不必亲自输入它,但这与您执行的操作相同:
// Evaluate the following in JS and copy into your code somewhere
// "type AllowableValues = "+
// Array.from({length: 5000}, (x, i) => String(i+1)+((i+1)%100?"":"\n")).join(" | ")+";";
// which produces:
type AllowableValues = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | // and so on
function getBlogs(limit?: AllowableValues) {
console.log((limit || 0).toFixed());
}
从某种意义上说,这将起作用,编译器将看到这limit
是联合(或undefined
)中的某个数值,并且getBlogs()
使用数字参数调用将对其进行验证:
getBlogs(100); // okay
getBlogs(1); // okay
getBlogs(1.5); // error!
// ----> ~~~
// Argument of type '1.5' is not assignable to
// parameter of type 1 | 2 | 3 | ...
getBlogs(0); // error!
// ----> ~
// Argument of type '0' is not assignable to
// parameter of type 1 | 2 | 3 | ...
getBlogs(-4);
// ----> ~~
// Argument of type '-4' is not assignable to
// parameter of type 1 | 2 | 3 | ...
当然,超出范围的任何事情都会失败:
getBlogs(1234567); // error (too big)
getBlogs(1e100); // error (too big)
这只有在人们getBlogs()
使用一些数字文字调用时才有效。数学运算往往会产生number
,它太宽而无法验证:
getBlogs(3+1); // error: safe but the compiler can't tell
此外,我注意到像上面这样的大型联合使我的 IDE 变得迟缓,所以我真的只建议对多达数百个的数字执行此操作。
另一种可能性是制作getBlogs()
一个通用函数,其中验证参数以确保它是一个正整数。我认为,您可以使用模板文字类型在 TypeScript 4.1 中完成此操作:
type AsPositiveWholeNumber<N extends number> =
N extends 0 ? PositiveWholeNumber :
number extends N ? PositiveWholeNumber :
`${N}` extends `${infer F}${"." | "-"}${infer L}` ?
PositiveWholeNumber : N
type PositiveWholeNumber = {
["Please choose a value that is a positive whole number"]: number
} & number
function getBlogs<N extends number>(limit?: AsPositiveWholeNumber<N>) {
console.log((limit || 0).toFixed());
}
在这里,该getBlogs()
函数接受一个limit
类型的参数AsPositiveWholeNumber<N>
,其中N
是一个number
- 约束类型参数,由传入的值推断limit
。该AsPositiveWholeNumber<N>
类型被设计为如果N
是一个正整数,那么AsPositiveWholeNumber<N>
将只是N
。否则,它将是PositiveWholeNumber
一个虚拟类型,其目的是为用户提供一个看似有用的错误消息。
重要的工作在里面完成AsPositiveWholeNumber<N>
。首先我们确保N
既不是number
也不是0
。然后我们通过模板文字类型将其转换为字符串`${N}`
,然后确保此字符串版本不N
包含"."
or"-"
字符。这应该主要将正整数与其他数字区分开来,至少在我们得到巨大的值之前,这些值是整数,但其字符串表示以带有小数点的指数表示法呈现(例如1.23456789e+23
)。
让我们看看它是否有效:
getBlogs(100); // okay
getBlogs(1); // okay
getBlogs(1.5); // error!
// ----> ~~~
// Argument of type '1.5' is not assignable to
// parameter of type 'PositiveWholeNumber | undefined'
getBlogs(0); // error!
// ----> ~
// Argument of type '0' is not assignable to
// parameter of type 'PositiveWholeNumber | undefined'
getBlogs(-4);
// ----> ~~
// Argument of type '-4' is not assignable to
// parameter of type 'PositiveWholeNumber | undefined'
getBlogs(1234567); // okay
getBlogs(1e100); // okay, but
getBlogs(11e98); // error: becomes 1.1e+99
getBlogs(3 + 1); // error: safe but the compiler can't tell
所以这也有效。它有同样的问题,您需要getBlogs()
使用数字文字进行调用,并且任何number
类型的参数都不会被接受。这个解决方案肯定比纯联合有更多奇怪的移动部件,所以我不确定我是否真的会在任何生产代码中推荐这个。但我确实想展示 TypeScript 当前与您期望的行为有多接近。
推荐阅读
- r - 在循环期间使用 rbind 添加 0 值
- node.js - 如何在当前 HTML 页面上使用 express 从 res.json 呈现 json 对象
- python - 如何更新用户输入之间的情节?
- firebase - 如何保护用作 Diaglogflow / Google Action 主机的 Google 云功能
- sql - 这个简单的 SQL 表达式有什么问题?
- cordova - 在应用程序购买 2 在 android 上返回交易数据 null
- elasticsearch - 根映射定义具有不受支持的参数:[_timestamp : {enabled=true}]
- python - 查找多个变量的每组行之间的相关性
- docker - 有没有办法创建一个不在默认位置的 docker 卷?
- python - 使用scrapy css从booking.com提取价格时出现问题