02257-medium-minusone

Back


type Mapping = {
  "1": "0";
  "2": "1";
  "3": "2";
  "4": "3";
  "5": "4";
  "6": "5";
  "7": "6";
  "8": "7";
  "9": "8";
};

type NumberToString<T extends number> = `${T}`;

type StringToArray<T extends string> = T extends `${infer A}${infer B}`
  ? [A, ...StringToArray<B>]
  : [];

type LastItemOfArray<T extends readonly any[]> = T extends [
  ...first: infer First,
  infer Last
]
  ? Last
  : T[0];

type MinusOneDigit<D extends string> = D extends keyof Mapping
  ? Mapping[D]
  : never;

type ArrayToString<T extends readonly any[]> = T extends [
  infer First,
  ...rest: infer Rest
]
  ? First extends string
    ? `${First}${ArrayToString<Rest>}`
    : ""
  : "";

type PopLast<T extends readonly any[]> = T extends [
  ...first: infer First,
  infer Last
]
  ? First
  : [];

type StringToNumber<T extends string> = T extends `${infer N extends number}`
  ? N
  : never;

type MinusOne<
  T extends number,
  S extends string[] = StringToArray<NumberToString<T>>
> = T extends 10
  ? 9
  : LastItemOfArray<S> extends "0"
  ? StringToNumber<`${MinusOne<StringToNumber<ArrayToString<PopLast<S>>>>}9`>
  : StringToNumber<`${ArrayToString<PopLast<S>>}${MinusOneDigit<
      LastItemOfArray<S>
    >}`>;

/* _____________ Test Cases _____________ */
import type { Equal, Expect } from "@type-challenges/utils";

type cases = [
  Expect<Equal<MinusOne<1>, 0>>,
  Expect<Equal<MinusOne<55>, 54>>,
  Expect<Equal<MinusOne<3>, 2>>,
  Expect<Equal<MinusOne<100>, 99>>,
  Expect<Equal<MinusOne<1101>, 1100>>,
  Expect<Equal<MinusOne<9_007_199_254_740_992>, 9_007_199_254_740_991>>
];

P.S. To run this, need increased --stack-size in node options.

Solution by comonadd #37533

type GetLengthedTuple<N extends number,Result extends any[]= []> = Result['length'] extends N ? Result: GetLengthedTuple<N,[...Result,Result['length']]>
// type t = GetLengthedTuple<54>
type MinusOne<N extends number, T extends any[] = GetLengthedTuple<N>> = T extends [any,...infer Rest]?Rest['length']:never

type Zero = MinusOne<1> // 0
type FiftyFour = MinusOne<55> // 54

Solution by Gravity2333 #37069

type GetNumber<T extends number, K extends any[] = []> = K['length'] extends T ? K : GetNumber<T, [...K, any]>
type MinusOne<T extends number> = T extends 0 ? 0 : GetNumber<T> extends [infer _F, ...infer R] ? R['length'] : never

Solution by 359Steve #37004

目前在挑战中等难度,这是最难的一集,硬控我一小时。。。 基本思路就是: 把number字面量转字符串,用SubtractOne映射实现一位的减法,然后用MinusOneByStr 处理,如果返回的是9,那么继续递归,最后再处理首位的0转回number字面量

type SubtractOne<T extends string> = 
  T extends '1' ? '0' :
  T extends '2' ? '1' :
  T extends '3' ? '2' :
  T extends '4' ? '3' :
  T extends '5' ? '4' :
  T extends '6' ? '5' :
  T extends '7' ? '6' :
  T extends '8' ? '7' :
  T extends '9' ? '8' : 
  T extends '0' ? '9' : never

type GetStringLast<S extends string> = S extends `${infer F}${infer Rest}` ? Rest extends '' ? F : GetStringLast<Rest> :never
type StringToNumber<S extends string> = S extends `${infer N extends number}` ? N : never;
type FilteZero<S extends string> = S extends `0${infer R}` ? R extends '' ? S : R : S
type MinusOneByStr<S extends string> = S extends `${infer Rest}${GetStringLast<S>}` 
  ? S extends `${Rest}${infer E}` 
    ? SubtractOne<E> extends '9' ? `${MinusOneByStr<Rest>}${SubtractOne<E>}` : `${Rest}${SubtractOne<E>}`
    : never
  : never
type MinusOne<T extends number> = StringToNumber<FilteZero<MinusOneByStr<`${T}`>>>

Solution by deerro #36977

type MinusOne<N extends number, T extends any[] = []> = T["length"] extends N
  ? T extends [infer L, ...infer Rest]
    ? Rest["length"]
    : 0
  : MinusOne<N, Push<T, N>>;

Solution by tingtingxiao0706 #36435

  1. 数字分解: 将数值转换为数字元组,便于逐位操作
  2. 模拟减法: 从最低位开始处理,实现借位逻辑
    • 非零位直接减一
    • 零位变为9并向高位借位
  3. 格式处理: 移除前导零并保留单个零值
  4. 结果转换: 将处理后的元组重新转换为数值类型 核心在于 MinusNumberTuple 精确模拟了手工减法的借位过程。
type DecMap = {9:8; 8:7; 7:6; 6:5; 5:4; 4:3; 3:2; 2:1; 1:0; 0:9;};

type DigitsToTuple<T extends string | number> =
  `${T}` extends `${infer A extends keyof DecMap}${infer B}`
    ? [A, ...DigitsToTuple<B>]
    : [];

type NumberTupleToString<T extends number[]> = T extends []
  ? ""
  : T extends [infer F extends number, ...infer R extends number[]]
  ? `${F}${NumberTupleToString<R>}`
  : never;

type StringToNumber<S extends string> = S extends `${infer N extends number}` ? N : never;
type RemoveZero<T extends number[]> = T extends [0, ...infer R extends number[]] ? R extends []  ? T  : R : T;

type MinusNumberTuple<T extends number[], R extends number[] = []> = T extends [
  ...infer A extends number[],
  infer B extends keyof DecMap
]
  ? B extends 0
    ? MinusNumberTuple<A, [DecMap[B], ...R]>
    : [...A, DecMap[B], ...R]
  : never;

type MinusOne<T extends number> = StringToNumber<NumberTupleToString<RemoveZero<MinusNumberTuple<DigitsToTuple<T>>>>>;

Solution by vowdemon #36326

// your answers
type MinusOne<T extends number, Tuple extends unknown[] = []> = T extends 0
    ? -1
    : [unknown, ...Tuple]["length"] extends T
    ? Tuple["length"]
    : MinusOne<T, [unknown, ...Tuple]>;

Solution by Sathiyapramod #35537

interface MinusMap {
  "9": "8";
  "8": "7";
  "7": "6";
  "6": "5";
  "5": "4";
  "4": "3";
  "3": "2";
  "2": "1";
  "1": "0";
}
type getLastCharOfString<S extends string> = S extends `${infer F}${infer R}`
  ? R extends ""
    ? F
    : getLastCharOfString<R>
  : never;

type ConvertString2Number<T extends string> = T extends `0${infer N}`
  ? N extends '' ? 0 : ConvertString2Number<N>
  : T extends `${infer M extends number}`
    ? M
    : never;

type MinusOneButString<T extends number, F = `${T}`> = F extends `${infer R extends number}0`
    ? `${MinusOneButString<R>}9`
    : F extends `${infer X}${infer R}`
      ? R extends ''
        ? X extends keyof MinusMap ? MinusMap[X] : never
        : F extends `${infer B}${getLastCharOfString<F>}`
          ? `${B}${MinusMap[getLastCharOfString<F>]}`
          : never
      : never;

// For number small than 0
// its same logic with the code above. Only need to get the oppisite direction of MinusMap
type MinusOne<T extends number> = T extends 0
  ? -1
  : ConvertString2Number<MinusOneButString<T>>;

Solution by Yaphet2015 #35176

type Map = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8]
type ReverseString<T extends string> = T extends `${infer First}${infer Rest}` ? `${ReverseString<Rest>}${First}` : T
type Decrease<T extends string> = T extends `${infer First extends number}${infer Rest}` ? `${Map[First]}${First extends 0 ? Decrease<Rest> : Rest}` : T
type ParseInt<T extends string> = T extends `${0}${infer Rest}` ? ParseInt<`${Rest}`> : (T extends `${infer N extends number}` ? N : 0)
type MinusOne<T extends number> = T extends 0 ? -1 : ParseInt<ReverseString<Decrease<ReverseString<`${T}`>>>>

Solution by 2083335157 #34894

type ParseInt<T extends string> = T extends `0${infer S}` ? ParseInt<S> : T extends `${infer R extends number}` ? R : 0

type Reverse<T extends string, S extends string = ''> = `${T}` extends `${infer L}${infer R}`? Reverse<R, `${L}${S}`> : S

type MinusOneWithout0<T extends number> = `${T}` extends `${infer R extends number}0`
? `${MinusOneWithout0<R>}9`
: Reverse<`${T}`> extends `${infer L extends number}${infer R}`
  ? Reverse<`${[9, 0, 1, 2, 3, 4, 5, 6, 7, 8][L]}${R}`>
  : never

type MinusOne<T extends number> = T extends 0
? -1
: ParseInt<MinusOneWithout0<T>>

Solution by hrc1457 #34851

// your answers
type Reverse<T extends string, R extends string = ''> = `${T}` extends `${infer First}${infer Rest}` ? Reverse<Rest, `${First}${R}`> : R;
type StringToNumber<T extends string> = T extends `${infer N extends number}`? N : never;
type TrimLeadingZero<T extends string> = T extends `0${infer Rest}` ? TrimLeadingZero<Rest> : T extends '' ? '0' : T;

type MinusOne<T extends number, R extends string = ''> = Reverse<`${T}`> extends `${infer First}${infer Rest}`
? First extends '0'
  ? Rest extends '' ? -1 : MinusOne<StringToNumber<Reverse<Rest>>, `${R}9`>
  : StringToNumber<TrimLeadingZero<Reverse<`${R}${MinusMap<First>}${Rest}`>>>
: never;

Solution by AndreGeng #34757

type Pop<T extends any[]> = T extends [...infer head, any] ? head : never; 

type MinusOne<T extends number, A extends any[] = []> = A['length'] extends T
  ? Pop<A>['length']
  : MinusOne<T, [...A, 0]>

Solution by devshinthant #34673

type MapMinusOne = {
  "0": "9";
  "1": "0";
  "2": "1";
  "3": "2";
  "4": "3";
  "5": "4";
  "6": "5";
  "7": "6";
  "8": "7";
  "9": "8";
};

// split number to tuple of digits
// eg.
// "12" -> ["1", "2"]
// "5" -> ["5"]
type SplitToDigit<A extends string> = A extends `${infer L}${infer R}`
  ? R extends ""
    ? [L]
    : [L, ...SplitToDigit<R>]
  : [];

// minus one from ones place
// eg.
// ["1", "2"] -> ["1", "1"]
// ["1", "0"] -> ["0", "9"]
// ["0"] -> ["-1"]
type MinusOneTuple<T extends string[]> = T extends [...infer L extends string[], infer R extends keyof MapMinusOne]
  ? R extends "0"
    ? L extends []
      ? ["-1"]
      : [...MinusOneTuple<L>, "9"]
    : [...L, MapMinusOne[R]]
  : [];

// eg.
// ["0", "9", "9"] -> ["9", "9"]
// ["0"] -> ["0"]
// ["1", "2"] -> ["1", "2"]
type RemoveHeadZero<T extends string[]> = T extends [infer L, ...infer R]
  ? L extends "0"
    ? R extends []
      ? ["0"]
      : R
    : T
  : [];

// eg.
// ["1", "2"] => "12"
type TupleToNumber<T extends string[]> = T extends [infer L extends string, ...infer R extends string[]]
  ? `${L}${TupleToNumber<R>}`
  : "";

type MinusOne<T extends number> = TupleToNumber<
  RemoveHeadZero<MinusOneTuple<SplitToDigit<`${T}`>>>
> extends `${infer U extends number}`
  ? U
  : never;

Solution by yukicountry #34410

type NumberMap = ['9', '0', '1', '2', '3', '4' ,'5', '6', '7', '8']

// number to char array
type NumToCharArr<T extends number | string> = `${T}` extends `${infer F}${infer R}` ? [F, ...NumToCharArr<R>] : []

// reverse array
type ReverseArr<T extends any[]> = T extends [infer F, ...infer R] ? [...ReverseArr<R>, F] : T

// char -1
type CharSubOne<T extends string> = T extends keyof NumberMap ? NumberMap[T] : never

// char array item -1
type ArrSubOne<T extends any[]> = T extends [infer F extends string, ...infer R]
    ? F extends '0'
        ? ['9', ...ArrSubOne<R>]
        : [CharSubOne<F>, ...R]
    : [];

// char array to string
type CharArrToStr<T extends any[]> = T extends [infer F extends string, ...infer R] ? `${F}${CharArrToStr<R>}` : ''

// string to number
type StrToNum<T extends string> = T extends `0${infer R}`
    ? StrToNum<R>
    : T extends `${infer R extends number}`
        ? R
        : 0;

type MinusOne<T extends number> = T extends 0 ? -1 : StrToNum<CharArrToStr<ReverseArr<ArrSubOne<ReverseArr<NumToCharArr<T>>>>>>

Solution by MAXLZ1 #34242

type ToNumber<T> = T extends `0${infer N extends number}` ? N : T extends `${infer N extends number}` ? N : T
type DigitToArr<T extends number, R extends unknown[] = []> = R['length'] extends ToNumber<T> ? R : DigitToArr<T, [...R, 0]>
type NumberToArr<T extends number | string, Arr extends unknown[][] = []> = `${T}` extends `${infer A extends number}${infer Rest}` ? NumberToArr<Rest, [...Arr, DigitToArr<A>]> : Arr
type MinusArr<R extends unknown[]> = R extends [...infer A, infer B] ? B extends [...infer R, infer _] ? [...A, R] : [...MinusArr<A>, DigitToArr<9>] : []
type ArrToString<Arr extends unknown[][], R = ''> = Arr extends [infer A extends unknown[], ...infer rest extends unknown[][]] ? `${A['length']}${ArrToString<rest>}` : R
type MinusOne<T extends number> = T extends 0 ? -1 : ToNumber<ArrToString<MinusArr<NumberToArr<T>>>>

Solution by ouzexi #34045

/* _____________ 你的代码 _____________ */

type ReverseString<S extends string> = 
  S extends `${infer First}${infer Rest}`
    ? `${ReverseString<Rest>}${First}`
    : "";


type DigitStrMinusOne<T extends string> = 
  "09876543210" extends `${string}${T}${infer Right}${string}`
    ? Right
    : never;


type RevNumStrMinusOne<T extends string> =
  T extends `${infer First}${infer Rest}`
    ? DigitStrMinusOne<First> extends `${infer Result}`
      ? Rest extends ""
        ? `${Result}`
        : Result extends "9"
          ? `${Result}${RevNumStrMinusOne<Rest>}`
          : `${Result}${Rest}`
      :never
    : "";


type DigitStrPlusOne<T extends string> = 
  "01234567890" extends `${string}${T}${infer Right}${string}`
    ? Right
    : never;


type RevNumStrPlusOne<T extends string> =
  T extends `${infer First}${infer Rest}`
    ? DigitStrPlusOne<First> extends `${infer Result}`
      ? Rest extends ""
        ? Result extends "0"
          ? `${Result}1`
          : `${Result}`
        : Result extends "0"
          ? `${Result}${RevNumStrPlusOne<Rest>}`
          : `${Result}${Rest}`
      :never
    : "";


type RemovePaddingZero<S extends string> =
  S extends `0${infer Rest}`
    ? Rest extends ""
      ? "0"
      : `${RemovePaddingZero<Rest>}`
    : S;


type MinusOne<T extends number> = 
  T extends 0
    ? -1
    : `${T}` extends `-${infer Digits}`
      ? `-${ReverseString<RevNumStrPlusOne<ReverseString<Digits>>>}` extends `${infer Result extends number}`
        ? Result
        : never
      : `${RemovePaddingZero<ReverseString<RevNumStrMinusOne<ReverseString<`${T}`>>>>}` extends `${infer Result extends number}`
        ? Result
        : never;

Solution by CarrickC #34001

// 你的答案

// 将数字转为对应长度的数组 如将2 转换为 [null, null]
type DigitToArray<T extends number, R extends any[] = []> = R['length'] extends T ? R : DigitToArray<T, [...R, null]>

// 将数字(字符串)的每一位都转为对应长度的数组,如将 '23' 转换为 [[null, null], [null, null, null]]
type WholeDigitStringToArray<T extends string, Res extends any[][] = []> = T extends `${infer A extends number}${infer R}` ? 
  WholeDigitStringToArray<R, [...Res, DigitToArray<A>]>
  : Res

// 将数字的每一位都转为对应长度的数组,如将 23 转换为 [[null, null], [null, null, null]]
type WholeDigitToArray<T extends number> = WholeDigitStringToArray<`${T}`>

// 翻转数组(要从个位 - 十位 - 百位 依次去减一)
type MyReverse<T extends any[], Res extends any[] = []> = T extends [...infer A, infer R] ? MyReverse<A, [...Res, R]> : Res

// 逐位减一,返回当前位减一的结果,及是否产生了借位
type MinusBitByBit<T extends any[]> = T extends [infer _, ...infer R] ? [R['length'], false] : [9, true]

// 将数组中的每一项展示为对应数组的长度 如将[[null, null], [null, null, null]] 转为 [2, 3]
type ArrayEveryToNumber<T extends any[][], Res extends any[] = []> = T extends [infer A extends any[], ...infer R extends any[][]] ? ArrayEveryToNumber<R, [...Res, A['length']]> : Res

// 数组整体减一操作
type WholeArrayMinusOne<T extends any[], Res extends any[] = []> = T extends [infer A extends any[], ...infer R extends any[]] ? 
 (MinusBitByBit<A> extends [infer X, infer Y] ? 
  Y extends true ? WholeArrayMinusOne<R, [...Res, X]> : [...Res, X, ...ArrayEveryToNumber<R>]
  : Res)
 : Res

// 将数组转为字符串
type ArrayToString<T extends any[], Res extends string = ''> = T extends [infer A extends number, ...infer R] ? ArrayToString<R, `${Res}${A}`> : Res

// 将字符串转为数字
type StringToNumber<T extends string> =T extends 0 ? 0 : T extends `0${infer A extends number}` ? A : T extends `${infer F extends number}` ? F : T

type MinusOne<T extends number> =T extends 0 ? -1 : StringToNumber<ArrayToString<MyReverse<WholeArrayMinusOne<MyReverse<WholeDigitToArray<T>>>>>>

Solution by heyuelan #33698

type NumberList = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8]; type ReverseStr<T extends string | number> = (T extends string ? T : ${T}) extends ${infer L}${infer R} ? ${ReverseStr<R>}${L} : T; type RemoveFirstZero = T extends ${infer L}${infer R} ? L extends '0' ? R extends '' ? ${T} : ${RemoveFirstZero<R>} : T : never; type Parse2Int = T extends any ? RemoveFirstZero extends ${infer N extends number} ? N : never : never; type LoopStr = T extends ${infer L extends number}${infer R} ? L extends 0 ? ${NumberList[L]}${LoopStr<R>} : ${NumberList[L]}${R} : ''; type MinusOne = T extends 0 ? -1 : Parse2Int<ReverseStr<LoopStr<ReverseStr>>>;

Solution by huangxinrui #33253

// your answers
type ReverseString<S extends string> = 
  S extends "" ? 
    S 
    :
    S extends `${infer c}${infer remaining}` ?
      `${ReverseString<remaining>}${c}`
      :never
;

type TrimLeadingZeros<T extends string> = 
  T extends '0' ?
    T
    :
    T extends `0${infer remaining}` ?
      TrimLeadingZeros<remaining>
      :
      T
;

type NumberToString<T extends number> = `${T}`;
type StringToNumber<T extends string> = TrimLeadingZeros<T> extends `${infer N extends number}`? N : never;




//only use for postive number
type MinusOneInternal<T extends number ,borrow extends boolean = false> = 
  ReverseString<NumberToString<T>> extends `${infer First extends number}${infer Remaining extends string}` ? 
    DigitMinusOne<First> extends  [ infer F extends number,infer Borrow extends boolean] ?
      Borrow extends true ?
        StringToNumber<`${MinusOneInternal<StringToNumber<ReverseString<Remaining>>,true>}${F}`>
        :
        StringToNumber<`${ReverseString<Remaining>}${F}`>
      :
      never
    :never;

//only use for postive number
type AddOneInteral<T extends number,carry extends boolean = false> = 
  ReverseString<NumberToString<T>> extends `${infer First extends number}${infer Remaining extends string}` ? 
    DigitAddOne<First> extends  [ infer F extends number,infer Carry extends boolean] ?
      Carry extends true ?
        Remaining extends "" ?
          StringToNumber<`1${F}`>
          :
          StringToNumber<`${AddOneInteral<StringToNumber<ReverseString<Remaining>>,true>}${F}`>
        :
        StringToNumber<`${ReverseString<Remaining>}${F}`>
      :
      never
    :NumberToString<T> extends "" ?
      carry extends true ?
        1
        :
        0
      :
      never; 

;

type DigitAddOne<n extends number > = 
  n extends 9 ?
   [0,true]
   :
   [[1,2,3,4,5,6,7,8,9][n],false] ;
        

;

type DigitMinusOne<n extends number > = 
  n extends 0 ?
   [9,true]
   :
   [[9,0,1,2,3,4,5,6,7,8][n],false] ;

type MinusOne<S extends number> = 
  S extends 0 ?
    -1
    :
    NumberToString<S> extends `-${infer positiveNumber extends number}` ? 
      `-${AddOneInteral<positiveNumber>}` extends `${infer num extends number}` ? 
        num
        :
        never
      :
      NumberToString<S> extends `${infer positiveNumber extends number}` ?
        MinusOneInternal<S,false>
        :
        never
        ;

Solution by sciencefunq #32929

type step1ParseInt<T extends string> = T extends `${infer Digit extends number}`?Digit : never;
type step2ReverseString<S extends string> = S extends `${infer First}${infer Rest}` ? `${step2ReverseString<Rest>}${First}` : ""
type step3RemoveLeadingZeros<S extends string> = S extends '0' ? S : S extends `${0}${infer Rest}` ? step3RemoveLeadingZeros<Rest>:S
type step4InternalMinusOne<S extends string> =
  S extends `${infer Digit extends number}${infer Rest}`?
  Digit extends 0?
    `9${step4InternalMinusOne<Rest>}`:
    `${[9, 0, 1, 2, 3, 4, 5, 6, 7, 8][Digit]}${Rest}`
  :never

type MinusOne<T extends number> = T extends 0? -1 :step1ParseInt<step3RemoveLeadingZeros<step2ReverseString<step4InternalMinusOne<step2ReverseString<`${T}`>>>>>

Solution by bananana0118 #32906

type StrToArr<T extends string, Arr extends string[] = []> =
  `${T}` extends `${infer A}${infer B}`
  ? StrToArr<B, [...Arr, A]>
  : Arr
type ParseInt<T extends string> =
  T extends `${infer A extends number}` ? A : never;
type InitArr<T extends number, Arr extends unknown[] = []> =
  Arr["length"] extends T ? Arr : InitArr<T, [...Arr, unknown]>
type SubTra<T extends number, K extends number> =
  InitArr<T> extends [...args: InitArr<K>, ...infer R] ? R['length'] : never;
type ArrToNum<T extends string[], Str extends string = ""> =
  T extends [infer A extends string, ...infer B extends string[]]
  ? ArrToNum<B, `${Str}${A}`>
  : ParseInt<Str>
type GreaterThan<T extends number, K extends number> =
  SubTra<T, K> extends never ? false : true;
type MinusOne<T extends number> = 
  T extends 0
  ? -1
  : GreaterThan<StrToArr<`${T}`>['length'],4> extends false
    ? SubTra<T,1>
    : StrToArr<`${T}`> extends [...infer A,infer B extends string]
      ? ParseInt<B> extends 0
        ? never
        : [...A,`${SubTra<ParseInt<B>,1>}`] extends [...infer A extends string[]]?ArrToNum<A>:never
      :never

有点取巧,判断小于4位数就直接使用SubTra减一即可,最好是在倒数第三行处处理一下0的情况,但是比较麻烦加上猪脑过载,没做出来QAQ

Solution by I-am-a-king-of-vue #32147

// 你的答案
// 由于有大数,递归会导致深度爆炸, 可以转成字符转进行运算
// -1 对照表
type reduceList = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8]
// 将字符串转为数字
type parseInt<T extends string> = T extends `${infer Digit extends number}` ? Digit : never;
// 翻转字符串
type reverseString<T extends string> = T extends `${infer F}${infer R}` ? `${reverseString<R>}${F}` : '';
// 去掉字符串前面所有的 0
type splitZero<T extends string> = T extends `${infer F}${infer L}` ? F extends '0' ? splitZero<L> : T : '0';
// 递归处理字符串
/**
 * 思路:
 * 1.每次取出最后一位, U 保存 -1 后的数字
 * 2.通过判断 U 是不是等于 '', 来判断当前位需不需要 -1 
 */
type recursiveString<T extends string, U extends string = '', Flag extends string = '0'> = T extends `${infer F}${infer L}`
  ? /** 当字符串可以拆开的时候,需要判断 U*/
    Flag extends '0' // Flag 如果是 '0', 说明当前字符不需要 -1
      ? `${reverseString<T>}${U}`
      : // Flag 如果是 '1', 说明当前字符需要 -1
        // 这里需要判断当前字符是否是 '0'
        F extends '0' 
          ? recursiveString<L, `${reduceList[parseInt<F>]}${U}`, '1'> // 0 下一位需要 -1
          : recursiveString<L, `${reduceList[parseInt<F>]}${U}`, '0'> // 非 0 下一位不需要 -1
  : /** 当字符串拆不开的时候, 说明上面的遍历到头了 */
    U extends '9' ? '-1' : splitZero<U>

type MinusOne<T extends number> = parseInt<recursiveString<reverseString<`${T}`>, '', '1'>>;

Solution by cutimgboy #31845

// Process...

Solution by jbalancer #31561

type ToNumber<S extends string> = S extends `${infer X extends number}` ? X : never;

type DigitMinusOne<
  T extends '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
> = {
  '9': '8',
  '8': '7',
  '7': '6',
  '6': '5',
  '5': '4',
  '4': '3',
  '3': '2',
  '2': '1',
  '1': '0'
}[T];

type LastChar<T extends string> = 
  T extends `${infer Head}${infer Tail}` 
    ? Tail extends '' 
      ? Head 
      : LastChar<Tail>
    : never
;

type MinusOneInternal<T extends string> = 
  T extends '1' 
    ? '' 
    : T extends `${infer U}0` 
      ? ToNumber<`${MinusOneInternal<U>}9`>
      : T extends `${infer U}${LastChar<T>}` 
        ? ToNumber<`${U}${DigitMinusOne<LastChar<T>>}`>
        : never
;

type MinusOne<T extends number> = 
  T extends 0 
    ? -1 
    : T extends 1 
      ? 0 
      : MinusOneInternal<`${T}`>
;

Solution by sdrjs #31513

// your answers
type mp = ['9', '0', '1', '2', '3', '4', '5', '6', '7', '8'];
type ParseInt<S> = S extends `${infer N extends number}` ? N : never;
type ReverseStr<S> = S extends `${infer F}${infer R}` ? `${ReverseStr<R>}${F}` : S;
// check S not 0
type _MinusOne<S extends string> = S extends `${infer F}${infer R}` ? F extends '0' ? `9${_MinusOne<R>}` : ParseInt<F> extends number ? `${mp[ParseInt<F>]}${R}` : never : never;
type _TrimLeftZero<S> = S extends `0${infer R}` ? _TrimLeftZero<R> : S;
type TrimLeftZero<S> = S extends `0` ? `0` : _TrimLeftZero<S>;
type __MinusOne<S extends number> = ParseInt<TrimLeftZero<ReverseStr<_MinusOne<ReverseStr<`${S}`>>>>>;
type MinusOne<S extends number> = S extends 0 ? -1 : __MinusOne<S>;

Solution by chenqy-yh #31079

type Digits = {
  '0': '9'
  '1': '0'
  '2': '1'
  '3': '2'
  '4': '3'
  '5': '4'
  '6': '5'
  '7': '6'
  '8': '7'
  '9': '8'
};
type StringToNumber<T extends string> = T extends `${infer A extends number}` ? A : never;
type Reverse<T extends string> = T extends `${infer H}${infer T}` ? `${Reverse<T>}${H}` : T;
type _MinusOne<T extends string> = 
T extends `${infer Head extends keyof Digits}${infer Tail}` 
? Head extends '0'
  ? `${_MinusOne<Tail>}${Digits[Head]}`
  : `${Reverse<Tail>}${Digits[Head]}`
: never;
type RemoveLeadingZero<S extends string> = S extends `${infer H extends '0'}${infer T}` ? T extends '' ? S : RemoveLeadingZero<T> : S;

type MinusOne<T extends number> = T extends 0 ? -1 : StringToNumber<RemoveLeadingZero<_MinusOne<Reverse<`${T}`>>>>;

Solution by korkota #31060

type MyTuple<Num extends number, Arr extends readonly unknown[] = []> = 
  Arr['length'] extends Num
    ? Arr
    : MyTuple<Num, [never, ...Arr]>


type MinusOne<T extends number> = MyTuple<T> extends [never, ...infer R] ? R['length'] : -1

Solution by HeeYeonKim98 #30838

This code creates excessive stack depth 💦

type SliceOne<Array extends unknown[]> = 
  Array extends [infer First, ...infer Rest]
    ? Rest
    : [];
type Push<Array extends unknown[]> = [1, ...Array];
type GetNumber<GoalNumber extends number, TargetArray extends unknown[]> = 
  TargetArray['length'] extends GoalNumber
    ? TargetArray
    : GetNumber<GoalNumber, Push<TargetArray>>;

type MinusOne<T extends number> = 
  // T extends [infer First, ...infer Rest extends unknown[]]['length']
  T extends (infer Arr extends unknown[])['length']
    ? SliceOne<GetNumber<T, []>>['length']
    : never;

Solution by KNHui #30832

type MakeNumberToArray<T extends number, U extends unknown[] = []> = U['length'] extends T
  ? U
  : MakeNumberToArray<T, [...U, 0]>;

type MinusOne<T extends number> = MakeNumberToArray<T> extends [infer R, ...infer U]
  ? R extends undefined
    ? 0
    : U['length']
  : never;

Solution by leejaehyup #30783

type ConstructTuple<Num extends number, Arr extends readonly never[] = []> = 
  Arr['length'] extends Num
    ? Arr
    : ConstructTuple<Num, [never, ...Arr]>


type MinusOne<T extends number> = ConstructTuple<T> extends [never, ...infer Rest] ? Rest['length'] : -1

Solution by GodAraden #30759