type ToNumber<S extends string> = S extends `${infer R extends number}` ? R : never
Solution by ouzexi #34223
type ToNumber<S extends string> = S extends `${infer Didgit extends number}` ? Didgit : never
Solution by PiligrimStas #33801
思路:
NumberUnion
S extends `${infer L extends NumberUnion}${infer Rest}`
// 这样L便可以推断成数字了(0-9)。
AddNumber
, 利用数组实现type AddNumber<N extends number, M extends number> = number extends N
? number extends M
? 0
: 0
: [...NumberToArr<N>, ...NumberToArr<M>]["length"] & number;
MultiplyTen
, 利用数组实现,写得比较死板type MultiplyTen<N extends number> = number extends N
? 0
: [
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>
]["length"] & number;
// 单个数字类型
type NumberUnion = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
// 将数字转为相同大小的数组 NumberToArr<3> // 结果是[1,1,1]
type NumberToArr<N extends number, Count extends 1[] = []> = Equal<
N,
Count["length"]
> extends true
? Count
: NumberToArr<N, [...Count, 1]>;
// 将两个数字相加 AddNumber<1, 2> // 3
type AddNumber<N extends number, M extends number> = number extends N
? number extends M
? 0
: 0
: [...NumberToArr<N>, ...NumberToArr<M>]["length"] & number;
// 将某个数字乘10 MultiplyTen<10> // 100
type MultiplyTen<N extends number> = number extends N
? 0
: [
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>,
...NumberToArr<N>
]["length"] &
number;
type ToNumber<
S extends string,
Res extends number = 0
> = S extends `${infer L extends NumberUnion}${infer Rest}`
? ToNumber<Rest, AddNumber<L, MultiplyTen<Res>>>
: S extends ""
? Res
: never;
Solution by Vampirelee #32618
type TStringToNumber<T> = T extends `${infer N extends number}` ? N : never;
type ParseInt<T extends string, Temp extends string = ''> = T extends `${infer First}${infer Rest}` ? (
First extends `${infer N extends number}` ? (
N extends number ? ParseInt<Rest, `${Temp}${N}`> : Temp
) : TStringToNumber<Temp>
) : TStringToNumber<Temp>;
type Test1 = ParseInt<'74,2'> //74
type Test2 = ParseInt<'3f'> //3
type Test3 = ParseInt<'hello'> //never
Solution by KarenGrigoryan1999 #30760
type ToNumber<S extends string> = S extends `${infer N extends number}` ? N : never
Solution by Chan-Yuxi #30526
// your answers
type ToNumber<S extends string, T extends any[] = []> = S extends `${number}` ? S extends `${T["length"]}`
? T["length"]
: ToNumber<S, [...T, any]> : never
Solution by AAA611 #28823
type ToNumber<S extends string> = S extends `${infer T extends number}`?T:never
Solution by jiangshanmeta #27908
There is the implementation I use in type-plus.
export type StringToNumber<S extends string, Fail = never> = S extends `-0`
? 0
: S extends `${infer W}.0`
? StringToNumber<W>
: S extends `${infer W}.${infer F}0`
? StringToNumber<`${W}.${F}`>
: S extends `${infer N extends number}`
? N
: Fail
It is used in part of StringToNumeric<S>
that works with both number
and bigint
.
It handles positive, negative, floating point numbers, and special cases (e.g. -0
and 1.0
).
Here are the unit test
🍻
Solution by unional #27561
type ToNumber<S extends string> = S extends `${infer N extends number}` ? N : never
Solution by smileboyi #27498
type Num = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
type FuNum<S> = S extends `-${infer R}` ? R : S
type isFu<S> = FuNum<S> extends never ? S : FuNum<S>
type isNum<S> = S extends `${infer R}${infer X}`
?
(R extends `${Num[number]}`
?
(X extends '' ? true : isNum<X>)
: false)
: never
type GetNum<S> = isNum<isFu<S>> extends true ? S : never
type A<S, Arr extends any[] = []> = S extends `${Arr['length']}` ? Arr['length'] : A<S, [S, ...Arr]>
type ToNumber<S extends string> = A<FuNum<GetNum<S>>>
// this's false ( +number To -number , i don't konw HELP ME! )
Expect<Equal<ToNumber<'-27'>, -27>>
Solution by Acoooooooer #26832
As of TypeScript 4.8 this has a super trivial one-line solution, but before that it was quite intense. The solutions on this video are more like an archaeological dig than anything else.
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'
type A1 = ToNumber<'0'>;
type B1 = 0;
type C1 = Expect<Equal<A1, B1>>;
type A2 = ToNumber<'5'>;
type B2 = 5;
type C2 = Expect<Equal<A2, B2>>;
type A3 = ToNumber<'12'>;
type B3 = 12;
type C3 = Expect<Equal<A3, B3>>;
type A4 = ToNumber<'27'>;
type B4 = 27;
type C4 = Expect<Equal<A4, B4>>;
type A5 = ToNumber<'18@7_$%'>;
type B5 = never;
type C5 = Expect<Equal<A5, B5>>;
// // ============= Your Code Here =============
// // /** TypeScript 4.8: https://devblogs.microsoft.com/typescript/announcing-typescript-4-8-beta/#infer-types-template-strings */
// type ToNumber<T> =
// T extends `${infer N extends number}`
// ? N
// : never;
// type ToNumber<
// T extends string,
// Count extends '🧮'[] = []
// > =
// T extends `${number}`
// ? T extends `${Count["length"]}`
// ? Count["length"]
// : ToNumber<T, [...Count, '🧮']>
// : never;
// // ================== NOPE ==================
// // Type instantiation is excessively deep
// // and possibly infinite.ts(2589)
// type ToNumber<
// T extends string,
// Count extends 1[] = []
// > =
// T extends `${Count["length"]}`
// ? Count["length"]
// : ToNumber<T, [...Count, 1]>;
// ============== Alternative ==============
// @uid11
type Num = readonly 0[]
/**
* NumToNumber<Num3> = 3, where Num3 = [0, 0, 0]
*/
type NumToNumber<N extends Num> = N['length']
type Digit =
| '0' | '1' | '2' | '3' | '4'
| '5' | '6' | '7' | '8' | '9'
/**
* MultiplyToDigit<'3', Num2> = Num6
*/
type MultiplyToDigit<D extends Digit, N extends Num> = {
'0': [],
'1': N,
'2': [...N, ...N],
'3': [...N, ...N, ...N],
'4': [...N, ...N, ...N, ...N],
'5': [...N, ...N, ...N, ...N, ...N],
'6': [...N, ...N, ...N, ...N, ...N, ...N],
'7': [...N, ...N, ...N, ...N, ...N, ...N, ...N],
'8': [...N, ...N, ...N, ...N, ...N, ...N, ...N, ...N],
'9': [...N, ...N, ...N, ...N, ...N, ...N, ...N, ...N, ...N],
}[D]
/**
* Num1
*/
type One = [0]
/**
* DigitToNum<'2'> = Num2
*/
type DigitToNum<D extends Digit> = MultiplyToDigit<D, One>
/**
* Sum<Num2, Num3> = Num5
*/
type Sum<N extends Num, M extends Num> = [...N, ...M]
/**
* MultiplyTo10<Num2> = Num20
*/
type MultiplyTo10<N extends Num> =
MultiplyToDigit<
'2',
MultiplyToDigit<'5', N>
>
/**
* GetBase<'2'> = Num10, GetBase<'31'> = Num100
*/
type GetBase<Number extends string> =
Number extends Digit
? MultiplyTo10<One>
: Number extends `${string}${infer Rest}`
? MultiplyTo10<GetBase<Rest>>
: never
/**
* StrToNum<'13'> = Num13
*/
type StrToNum<Str extends string> = Str extends Digit
? MultiplyToDigit<Str, One>
: Str extends `${infer D}${infer Rest}`
? D extends Digit
? Sum<
MultiplyToDigit<D, GetBase<Rest>>,
StrToNum<Rest>
>
: never
: never
/**
* ToNumber<'24'> = 24
*/
type ToNumber<S extends string> = NumToNumber<StrToNum<S>>
For more video solutions to other challenges: see the umbrella list! https://github.com/type-challenges/type-challenges/issues/21338
Solution by dimitropoulos #25923
type ToNumber<S extends string> = S extends `${infer R extends number}` ? R : never;
Solution by E-uler #24767
// your answers
type ToNumber<S extends string> = S extends `${infer N extends number}`
? N
:never
Solution by walker-hzx #24604
type ToNumber<S extends string> = S extends `${infer IsNumber extends number}` ? IsNumber : never
Solution by NeylonR #24446
// your answers
type ToNumber<S extends string> = S extends `${infer F extends number}` ? F : never
Solution by snakeUni #23514
// your answers
type ToNumber<S extends string> = S extends `${infer R extends number}` ? R : never;
Solution by jxhhdx #22856
// your answers
type StringNumber = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
type IsNumber<S extends string> =
S extends `${infer First}${infer Rest}`
? First extends (StringNumber | '.' )
? IsNumber<Rest>
: false
: never
type StringNumberArray<S extends string, R extends 1[] = [], MAX = 1000> =
`${R['length']}` extends S
? R
: MAX extends R['length']
? []
: StringNumberArray<S, [...R, 1]>
type GetInt<S> = S extends `${infer Int}.${infer Rest}` ? Int : S
type ToNumber<S extends string> = IsNumber<S> extends true ? StringNumberArray<GetInt<S>> extends any[] ? StringNumberArray<GetInt<S>>['length'] : never : never
Solution by 437204933 #22296
type ToNumber<S extends string> =
S extends `${infer N extends number}`
? N
: never
Solution by drylint #22218
// your answers
type NumberMap = {
"0": 0;
"1": 1;
"2": 2;
"3": 3;
"4": 4;
"5": 5;
"6": 6;
"7": 7;
"8": 8;
"9": 9;
};
// 两数相加
type Add<
A extends number,
B extends number,
CountA extends 0[] = [],
CountB extends 0[] = []
> = CountA["length"] extends A
? CountB["length"] extends B
? [...CountA, ...CountB]["length"]
: Add<A, B, CountA, [0, ...CountB]>
: CountB["length"] extends B
? Add<A, B, [0, ...CountA], CountB>
: Add<A, B, [0, ...CountA], [0, ...CountB]>;
// 两数相乘
// 2 x 5 = 2 + 2 + 2 + 2
type Mul<
A extends number,
B extends number,
Res extends number = 0,
Cnt extends 0[] = []
> = Cnt["length"] extends B ? Res : Mul<A, B, Add<A, Res>, [0, ...Cnt]>;
type ToNumber<
T extends string,
Res extends number = 0
> = T extends `${infer F}${infer R}`
? F extends keyof NumberMap
? ToNumber<R, Add<Mul<Res, 10>, NumberMap[F]>>
: never
: Res;
Solution by acwink #22092
type ToNumber<S extends string> = S extends `${infer N extends number}` ? N : never;
Solution by Karamuto #21952
type StringToUnion<T extends string> = T extends `${infer First}${infer Rest}` ? First | StringToUnion<Rest> : never;
type Numbers = StringToUnion<'0123456789'>;
type TrimZero<T extends string | never> = T extends `${infer First}${infer Rest}`
? First extends '0'
? TrimZero<Rest>
: T
: T;
type T1 = TrimZero<'0012'>;
type T2 = TrimZero<'10012'>;
type T3 = TrimZero<'12'>;
type T4 = TrimZero<'0000'>;
type StringToNumberString<
T extends string,
Result extends string | never = never
> = T extends `${infer First}${infer Rest}`
? First extends Numbers
? StringToNumberString<Rest, `${[Result] extends [never] ? `${First}` : `${Result}${First}`}`>
: Result
: Result;
type N1 = StringToNumberString<'ABC'>;
type N2 = StringToNumberString<'0'>;
type N3 = StringToNumberString<'5'>;
type N4 = StringToNumberString<'12'>;
type N5 = StringToNumberString<'27'>;
type N6 = StringToNumberString<'18@7_$%'>;
type N7 = StringToNumberString<'27.12'>;
type N8 = StringToNumberString<'012'>;
type N9 = StringToNumberString<'000012'>;
type N10 = StringToNumberString<'0000.12'>;
type StringToIntNumberString<T extends string> = TrimZero<StringToNumberString<T>>;
type NI1 = StringToIntNumberString<'ABC'>;
type NI2 = StringToIntNumberString<'0'>;
type NI3 = StringToIntNumberString<'5'>;
type NI4 = StringToIntNumberString<'12'>;
type NI5 = StringToIntNumberString<'27'>;
type NI6 = StringToIntNumberString<'18@7_$%'>;
type NI7 = StringToIntNumberString<'27.12'>;
type NI8 = StringToIntNumberString<'012'>;
type NI9 = StringToIntNumberString<'000012'>;
type NI10 = StringToIntNumberString<'0000.12'>;
type ToNumber<T extends string, Result extends any[] = [], NT = StringToIntNumberString<T>> = [NT] extends [never]
? never
: NT extends ''
? 0
: `${Result['length']}` extends NT
? Result['length']
: ToNumber<T, [...Result, 1]>;
type TN1 = ToNumber<'ABC'>;
type TN2 = ToNumber<'0'>;
type TN3 = ToNumber<'5'>;
type TN4 = ToNumber<'12'>;
type TN5 = ToNumber<'27'>;
type TN6 = ToNumber<'18@7_$%'>;
type TN7 = ToNumber<'27.12'>;
type TN8 = ToNumber<'012'>;
type TN9 = ToNumber<'000012'>;
type TN10 = ToNumber<'0000.12'>;
type TN11 = ToNumber<'A19'>;
Solution by zqiangxu #21512
// your answers
// new function
type ToNumber<S extends string> = S extends `${infer F1 extends number}` ? F1 : never;
Solution by venusliang #20857
// your answers
type CreateArrBylen<T extends number,Arr extends any[] = []> = Arr['length'] extends T ? Arr : CreateArrBylen<T, Arr extends [...infer Rest] ? [...Rest,1] : []>
type IncreaseArr<T extends any[]> = T extends [...infer R] ? T['length'] extends 100 ? never : [...R,1]['length'] : never
type ToNumber<S extends string,Count extends number | never = 0> = Count extends never ? never : S extends `${Count}` ? Count : ToNumber<S,IncreaseArr<CreateArrBylen<Count>>>
Solution by YqxLzx #20656
type ToNumber<S extends string> = S extends `${infer A extends number}` ? A : never
Solution by zhaoyao91 #20491
// your answers
type TN<
S extends string,
arr extends unknown[] = []
> = `${arr["length"]}` extends `${S}` ? arr["length"] : TN<S, [...arr, 1]>;
// slow ? haha
Solution by fengjinlong #20240
// EASY
type ToNumber<S extends string> = S extends `${infer N extends number}` ? N : never
// SO SO SO stupid ANSWER
/**
* 1. 提取 str num
* 2. 将 str num =》 numer[]
* 3. 按照数字的长度进行拼接;例如:100
* - 1) IdxToSinal【0】* Num1 + IdxToSinal【1】* Num2 + 1IdxToSinal【2】* Num3
*/
type IdxToSinal = {
0: 1,
1: 10,
2: 100,
3: 1000,
4: 10000
}
type strMap = {
'0': 0
'1': 1
'2': 2
'3': 3
'4': 4
'5': 5
'6': 6
'7': 7
'8': 8
'9': 9
}
// utils
type NumToArr<T, Ret extends any[] = []> = 0 extends 1 ? never : Ret['length'] extends T ? Ret : NumToArr<T, [...Ret, unknown]>
type Multiplication<S extends number, N extends number, SA extends any[] = NumToArr<S>, NA extends any[] = NumToArr<N>, Ret extends any[] = []> = NA extends [infer First, ...infer Rest] ? Multiplication<S, N, SA, Rest, [...Ret, ...SA]> : Ret
type res = Multiplication<10, 5>['length']
// step1 & step2
type StrToNumberList<S extends string, Ret extends number [] = []> = S extends `${infer First extends keyof strMap}${infer Rest}` ? StrToNumberList<Rest, [...Ret,strMap[First]]> : Ret
// step3
type getNumFromIdxMap<T extends any[]> = T['length'] extends keyof IdxToSinal ? IdxToSinal[T['length']] : 0
type AccNum<T extends number[],CurIdx extends any[] = [], Ret extends any[] = []> = T extends [ ...infer Rest extends number[],infer First extends number] ? AccNum<Rest, [...CurIdx, unknown], [...Ret, ...Multiplication<getNumFromIdxMap<CurIdx>,First>]> : Ret['length']
type ToNumber<S extends string> = S extends `${number}` ? AccNum<StrToNumberList<S>> : never
Solution by Rebornjiang #20237
type Numbers = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '0'
type CheckString<S> = S extends `${infer First}${infer Tail}`
? First extends Numbers
? CheckString<Tail> : false
: true
type ToNumber<S extends string, Arr extends any[] = []> = CheckString<S> extends false
? never : S extends `${Arr['length']}`
? Arr['length'] : ToNumber<S, [1, ...Arr]>
Solution by Zhukov87 #19673
type StringToUnion<T extends string> = T extends `${infer F}${infer R}` ? F | StringToUnion<R> : never;
type Number = StringToUnion<'0123456789'>;
type ToNumber<S extends string, Arr extends 0[] = []> = StringToUnion<S> extends Number ?
`${Arr['length']}` extends S ?
Arr['length'] :
ToNumber<S, [...Arr, 0]> :
never;
Solution by CallMeSaltyF1sh #19440
type SingleNumber = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
type IsCanConvert<S extends string> = S extends `${infer F}${infer R}` ? (F extends SingleNumber ? IsCanConvert<R> : false) : true;
type ToNumber<S extends string, N extends any[] = []> = IsCanConvert<S> extends true ? (`${N['length']}` extends S ? N['length'] : ToNumber<S, [...N, 1]>) : never;
Solution by CaoXueLiang #19036
type ArrayBase = {
"0": [],
"1": [unknown],
"2": [unknown, unknown],
"3": [unknown, unknown, unknown],
"4": [unknown, unknown, unknown, unknown],
"5": [unknown, unknown, unknown, unknown, unknown],
"6": [unknown, unknown, unknown, unknown, unknown, unknown],
"7": [unknown, unknown, unknown, unknown, unknown, unknown, unknown],
"8": [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown],
"9": [unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown]
}
type NumStrToArray<T extends string, A extends unknown[] = []> = T extends `${infer F}${infer R}`
? F extends keyof ArrayBase
? NumStrToArray<R, [...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...A, ...ArrayBase[F]]>
: never
: A
type num = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
type IsNumber<T> = T extends `${num}${infer S}`
? IsNumber<S>
: T extends ''
? true
: false
type ToNumber<S extends string> = IsNumber<S> extends true
? NumStrToArray<S>['length']
: never
type ToNumber<S extends string> = S extends `${infer N extends number}` ? N : never
Solution by milletlovemouse #18825