代码之家  ›  专栏  ›  技术社区  ›  Ilijanovic

typescript参数中允许的最小数目

  •  0
  • Ilijanovic  · 技术社区  · 4 年前

    我的功能如下:

    function getBlogs(limit?: number) { ... }
    

    这个 limit 只能是正整数,不能是 0

    如何告诉typescript该数字只能大于0?

    0 回复  |  直到 4 年前
        1
  •  5
  •   jcalz    4 年前

    有一个公开的建议, microsoft/TypeScript#15480 支持“范围类型”,您可以这样说, type PositiveWholeNumbers = 1..9999999 代表您的类型。还有一个(封闭的)建议 microsoft/TypeScript#4639 支持 int uint -就像类型一样,也可能在这里工作。遗憾的是,这两个都没有实现,因此如果您想在类型系统中实现这一点,您需要做一些其他的事情。


    如果有一个合理的小上限(以千为单位 最多 ),您可以手动生成 union 并将其放入库文件中的某个位置。这可以通过编程方式完成,因此您不必实际键入,但这与您键入的内容相同:

    // 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() A. generic 函数,在此函数中验证参数以确保其为正整数。我认为,您可以在TypeScript 4.1中使用 template literal types :

    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() 函数接受 限度 类型的参数 AsPositiveWholeNumber<N> 哪里 N 是一个 数字 -由的值推断的约束类型参数 限度 已传入。这个 AsPositiveWholeNumber<N> 类型的设计应确保 N 是一个正整数,那么 AsPositiveWholeNumber<N> 只会是 N .否则 PositiveWholeNumber ,一种虚拟类型,其目的是向用户提供一条看似有用的错误消息。

    重要的工作在内部完成 AsPositiveWholeNumber<N> .首先我们要确保 N 两者都不是 数字 也没有 0 。然后通过模板文本类型将其转换为字符串 `${N}` 然后确保 N 不包含 "." "-" 字符。这应该主要区分正整数和其他数字,至少在我们得到 巨大的 值,这些值是整数,但其字符串表示形式以带小数点的指数表示法呈现(例如 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() 用一个数字文字 数字 -将不接受类型化参数。这个解决方案肯定比纯联合有更多奇怪的运动部件,所以我不确定我真的会在任何生产代码中推荐它。但我确实想展示TypeScript目前与您期望的行为有多接近。


    Playground link to code