Typescript:增量数字类型

c9qzyr3d  于 2023-04-22  发布在  TypeScript
关注(0)|答案(4)|浏览(141)

是否可以从数字类型T得到值为T+1的数字类型Y

type one = 1

type Increment<T extends number> = ???

type two = Increment<one> // 2

P.S.目前,我已经硬编码了递增值的接口,但问题是硬编码的,因此受到限制:

export type IncrementMap = {
    0: 1,
    1: 2,
    2: 3,
gg58donl

gg58donl1#

我会像这样硬编码:

type Increment<N extends number> = [
  1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
  21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,
  38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54, // as far as you need
  ...number[] // bail out with number
][N]

type Zero = 0
type One = Increment<Zero> // 1
type Two = Increment<One>  // 2

type WhoKnows = Increment<12345>; // number

正如我在其他评论中所说,目前还没有对这种自然递归类型的支持。如果支持它,我会很高兴,但它并不存在。在实践中,我发现如果某个东西可以处理长度为20左右的元组,那就足够好了,但你的经验可能会有所不同。
无论如何,如果有人在这里提出了一个解决方案,它不是硬编码的,但对于任意数字(其中Increment<123456789>的计算结果为123456790)也能很好地工作和执行,我很有兴趣看看它。也许将来有一天它会成为语言的一部分。
希望有帮助;祝你好运!

5fjcxozz

5fjcxozz2#

这个解决方案不是硬编码的,但由于TypeScript的递归限制,它并没有什么用处。当我测试它时,它不能处理大于45的Number2Nat

type SomeNat = [...unknown[]];
type Zero = [];
type Succ<N extends SomeNat> = [...N, unknown];
type Nat2Number<N extends SomeNat> = N["length"];
type Dec<N extends SomeNat> = N extends [unknown, ...infer T] ? T : never;
type Add<N extends SomeNat, M extends SomeNat> = [...N, ...M];
type Sub<N extends SomeNat, M extends SomeNat> = M extends Zero ? N : Sub<Dec<N>, Dec<M>>;
type Number2Nat<I extends number, N extends SomeNat = Zero> = I extends Nat2Number<N> ? N : Number2Nat<I, Succ<N>>;
nr7wwzry

nr7wwzry3#

一个稍有不同的解决方案。但是有同样的1000次递归调用的限制

type Arr<N extends number, T extends any[] = []> = T['length'] extends N ? T : Arr<N, [...T, any]>

type Inc<N extends number> = [...Arr<N>, any]['length']

type I20 = Inc<19>
bwitn5fc

bwitn5fc4#

下面的解决方案没有递归限制n > 999。唯一的限制是n.toString().length > 1000;这似乎是javascript识别数字的能力的一个极限,一旦超过这个极限,typescript将把递增的类型显示为number

type IncrementMap = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
type LastDigitMap = {
  10: 0;
  11: 1;
  12: 2;
  13: 3;
  14: 4;
  15: 5;
  16: 6;
  17: 7;
  18: 8;
};

type LastCharacter<T extends string> = T extends `${infer First}${infer Last}`
  ? Last extends ''
    ? First
    : LastCharacter<Last>
  : T;

export type _Increment<
  Number extends string,
  Carry extends 0 | 1 = 0,
  Result extends string = '',
> = Number extends ''
  ? Carry extends 0
    ? Result
    : `${Carry}${Result}`
  : LastCharacter<Number> extends `${infer LastDigit extends number}`
  ? IncrementMap[LastDigit] extends infer Incremented extends number
    ? Number extends `${infer Rest}${LastDigit}`
      ? Incremented extends keyof LastDigitMap
        ? _Increment<Rest, 1, `${LastDigitMap[Incremented]}${Result}`>
        : `${Rest}${Incremented}${Result}`
      : never
    : never
  : never;

type Increment<T extends number> = _Increment<
  `${T}`,
  1
> extends `${infer Result extends number}`
  ? Result
  : never;

type Case1 = Increment<1>;
type Case2 = Increment<9>;
type Case3 = Increment<999>;
type Case4 = Increment<1899999999999999>;

给定解决方案的逻辑类似于将大数字求和为一个字符串。我们从最右边的字符开始,然后加1。
加法是用IncrementMap类型完成的,其中索引是我们试图递增的数字,值是我们想要获得的实际递增数字。
链接到playground

相关问题