Skip to content

Commit 7761f91

Browse files
authored
Add Absolute type (#1391)
1 parent b0b92ae commit 7761f91

File tree

9 files changed

+153
-37
lines changed

9 files changed

+153
-37
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ export type {TupleOf} from './source/tuple-of.d.ts';
173173
export type {ExclusifyUnion} from './source/exclusify-union.d.ts';
174174
export type {ArrayReverse} from './source/array-reverse.d.ts';
175175
export type {UnionMember} from './source/union-member.d.ts';
176+
export type {Absolute} from './source/absolute.d.ts';
176177

177178
// Template literal types
178179
export type {CamelCase, CamelCaseOptions} from './source/camel-case.d.ts';

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ Click the type names for complete docs.
294294
- [`LessThanOrEqual`](source/less-than-or-equal.d.ts) - Returns a boolean for whether a given number is less than or equal to another number.
295295
- [`Sum`](source/sum.d.ts) - Returns the sum of two numbers.
296296
- [`Subtract`](source/subtract.d.ts) - Returns the difference between two numbers.
297+
- [`Absolute`](source/absolute.d.ts) - Returns the absolute value of the specified number or bigint.
297298

298299
### Change case
299300

source/absolute.d.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type {StringToNumber} from './internal/string.d.ts';
2+
3+
/**
4+
Returns the absolute value of the specified number or bigint.
5+
6+
@example
7+
```
8+
import type {Absolute} from 'type-fest';
9+
10+
type A = Absolute<-1>;
11+
//=> 1
12+
13+
type B = Absolute<1>;
14+
//=> 1
15+
16+
type C = Absolute<0>;
17+
//=> 0
18+
19+
type D = Absolute<-1.025>;
20+
//=> 1.025
21+
22+
type E = Absolute<-9999n>;
23+
//=> 9999n
24+
```
25+
26+
Returns back the same type if the input is not a literal type.
27+
28+
@example
29+
```
30+
import type {Absolute} from 'type-fest';
31+
32+
type A = Absolute<number>;
33+
//=> number
34+
35+
type B = Absolute<bigint>;
36+
//=> bigint
37+
38+
type C = Absolute<number | bigint>;
39+
//=> number | bigint
40+
```
41+
42+
@category Numeric
43+
*/
44+
export type Absolute<N extends number | bigint> = N extends bigint // Also, distributes `N`
45+
? `${N}` extends `-${infer Magnitude extends bigint}`
46+
? Magnitude
47+
: N
48+
: `${N}` extends `-${infer Magnitude}` // This doesn't use the `extends number` constraint approach because that fails with the `-Infinity` case
49+
? StringToNumber<Magnitude>
50+
: N;
51+
52+
export {};

source/greater-than.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import type {NumberAbsolute, PositiveNumericStringGt} from './internal/index.d.ts';
1+
import type {PositiveNumericStringGt} from './internal/index.d.ts';
22
import type {IsEqual} from './is-equal.d.ts';
33
import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric.d.ts';
44
import type {And} from './and.d.ts';
55
import type {Or} from './or.d.ts';
6+
import type {Absolute} from './absolute.d.ts';
67

78
/**
89
Returns a boolean for whether a given number is greater than another number.
@@ -82,7 +83,7 @@ export type GreaterThan<A extends number, B extends number> =
8283
? true
8384
: [false, false] extends R
8485
? PositiveNumericStringGt<`${A}`, `${B}`>
85-
: PositiveNumericStringGt<`${NumberAbsolute<B>}`, `${NumberAbsolute<A>}`>
86+
: PositiveNumericStringGt<`${Absolute<B>}`, `${Absolute<A>}`>
8687
: never
8788
: never
8889
: never // Should never happen

source/internal/numeric.d.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,8 @@
11
import type {IsNever} from '../is-never.d.ts';
22
import type {Finite, NegativeInfinity, PositiveInfinity} from '../numeric.d.ts';
33
import type {UnknownArray} from '../unknown-array.d.ts';
4-
import type {StringToNumber} from './string.d.ts';
54
import type {IfNotAnyOrNever, IsAnyOrNever} from './type.d.ts';
65

7-
/**
8-
Returns the absolute value of a given value.
9-
10-
@example
11-
```
12-
type A = NumberAbsolute<-1>;
13-
//=> 1
14-
15-
type B = NumberAbsolute<1>;
16-
//=> 1
17-
18-
type C = NumberAbsolute<NegativeInfinity>;
19-
//=> PositiveInfinity
20-
```
21-
*/
22-
export type NumberAbsolute<N extends number> = `${N}` extends `-${infer StringPositiveN}` ? StringToNumber<StringPositiveN> : N;
23-
246
/**
257
Check whether the given type is a number or a number string.
268

source/subtract.d.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import type {NumberAbsolute, ReverseSign} from './internal/index.d.ts';
1+
import type {ReverseSign} from './internal/index.d.ts';
22
import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric.d.ts';
33
import type {LessThan} from './less-than.d.ts';
44
import type {TupleOf} from './tuple-of.d.ts';
5+
import type {Absolute} from './absolute.d.ts';
56

67
/**
78
Returns the difference between two numbers.
@@ -59,9 +60,9 @@ type SubtractPostChecks<A extends number, B extends number, AreNegative = [IsNeg
5960
? SubtractPositives<A, B>
6061
: AreNegative extends [true, true]
6162
// When both numbers are negative we subtract the absolute values and then reverse the sign
62-
? ReverseSign<SubtractPositives<NumberAbsolute<A>, NumberAbsolute<B>>>
63+
? ReverseSign<SubtractPositives<Absolute<A>, Absolute<B>>>
6364
// When the signs are different we can add the absolute values and then reverse the sign if A < B
64-
: [...TupleOf<NumberAbsolute<A>>, ...TupleOf<NumberAbsolute<B>>] extends infer R extends unknown[]
65+
: [...TupleOf<Absolute<A>>, ...TupleOf<Absolute<B>>] extends infer R extends unknown[]
6566
? LessThan<A, B> extends true ? ReverseSign<R['length']> : R['length']
6667
: never;
6768

source/sum.d.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import type {TupleOf} from './tuple-of.d.ts';
2-
import type {NumberAbsolute, TupleMax, ReverseSign} from './internal/index.d.ts';
2+
import type {TupleMax, ReverseSign} from './internal/index.d.ts';
33
import type {PositiveInfinity, NegativeInfinity, IsNegative} from './numeric.d.ts';
44
import type {Subtract} from './subtract.d.ts';
5+
import type {Absolute} from './absolute.d.ts';
56

67
/**
78
Returns the sum of two numbers.
@@ -57,11 +58,11 @@ type SumPostChecks<A extends number, B extends number, AreNegative = [IsNegative
5758
? SumPositives<A, B>
5859
: AreNegative extends [true, true]
5960
// When both numbers are negative we add the absolute values and then reverse the sign
60-
? ReverseSign<SumPositives<NumberAbsolute<A>, NumberAbsolute<B>>>
61+
? ReverseSign<SumPositives<Absolute<A>, Absolute<B>>>
6162
// When the signs are different we can subtract the absolute values, remove the sign
6263
// and then reverse the sign if the larger absolute value is negative
63-
: NumberAbsolute<Subtract<NumberAbsolute<A>, NumberAbsolute<B>>> extends infer Result extends number
64-
? TupleMax<[NumberAbsolute<A>, NumberAbsolute<B>]> extends infer Max_ extends number
64+
: Absolute<Subtract<Absolute<A>, Absolute<B>>> extends infer Result extends number
65+
? TupleMax<[Absolute<A>, Absolute<B>]> extends infer Max_ extends number
6566
? Max_ extends A | B
6667
// The larger absolute value is positive, so the result is positive
6768
? Result

test-d/absolute.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import {expectType} from 'tsd';
2+
import type {Absolute} from '../source/absolute.d.ts';
3+
import type {NegativeInfinity, PositiveInfinity} from '../source/numeric.d.ts';
4+
5+
// Integers
6+
expectType<Absolute<0>>(0);
7+
expectType<Absolute<1>>(1);
8+
expectType<Absolute<-1>>(1);
9+
expectType<Absolute<100>>(100);
10+
expectType<Absolute<-100>>(100);
11+
12+
// Bigints
13+
expectType<Absolute<0n>>(0n);
14+
expectType<Absolute<512n>>(512n);
15+
expectType<Absolute<-512n>>(512n);
16+
expectType<Absolute<9_999_999_999_999_999n>>(9_999_999_999_999_999n);
17+
expectType<Absolute<-9_999_999_999_999_999n>>(9_999_999_999_999_999n);
18+
19+
// Infinity
20+
expectType<Absolute<PositiveInfinity>>({} as PositiveInfinity);
21+
expectType<Absolute<NegativeInfinity>>({} as PositiveInfinity);
22+
23+
// Decimals
24+
expectType<Absolute<3.1428>>(3.1428);
25+
expectType<Absolute<-3.1428>>(3.1428);
26+
expectType<Absolute<0.5>>(0.5);
27+
expectType<Absolute<-0.5>>(0.5);
28+
29+
// Numeric separators
30+
expectType<Absolute<1_000_000>>(1_000_000);
31+
expectType<Absolute<-1_000_000>>(1_000_000);
32+
expectType<Absolute<1_000_000n>>(1_000_000n);
33+
expectType<Absolute<-1_000_000n>>(1_000_000n);
34+
35+
// Binaries
36+
expectType<Absolute<0b10>>(0b10);
37+
expectType<Absolute<-0b10>>(0b10);
38+
expectType<Absolute<0b11_1000n>>(0b11_1000n);
39+
expectType<Absolute<-0b11_1000n>>(0b11_1000n);
40+
41+
// Octals
42+
expectType<Absolute<0o70>>(0o70);
43+
expectType<Absolute<-0o70>>(0o70);
44+
expectType<Absolute<0o77_7000n>>(0o77_7000n);
45+
expectType<Absolute<-0o77_7000n>>(0o77_7000n);
46+
47+
// Hexadecimals
48+
expectType<Absolute<0xF0>>(0xF0);
49+
expectType<Absolute<-0xF0>>(0xF0);
50+
expectType<Absolute<0xFF_F0_00n>>(0xFF_F0_00n);
51+
expectType<Absolute<-0xFF_F0_00n>>(0xFF_F0_00n);
52+
53+
// Scientific notations
54+
expectType<Absolute<6.022e23>>(6.022e23);
55+
expectType<Absolute<-6.022e23>>(6.022e23);
56+
expectType<Absolute<6.626e-34>>(6.626e-34);
57+
expectType<Absolute<-6.626e-34>>(6.626e-34);
58+
expectType<Absolute<3e8>>(3e8);
59+
expectType<Absolute<-1.2345e2>>(1.2345e2);
60+
61+
// Non literals
62+
expectType<number>({} as Absolute<number>);
63+
expectType<bigint>({} as Absolute<bigint>);
64+
expectType<number | bigint>({} as Absolute<number | bigint>);
65+
66+
// Unions
67+
// 1. Literal members
68+
expectType<Absolute<0 | 1 | 2>>({} as 0 | 1 | 2);
69+
expectType<Absolute<2 | 4 | 8 | 16>>({} as 2 | 4 | 8 | 16);
70+
expectType<Absolute<-98_765n | -12_345n>>({} as 98_765n | 12_345n);
71+
expectType<Absolute<-2 | -1 | 0>>({} as 2 | 1 | 0);
72+
expectType<Absolute<2 | -2>>(2);
73+
expectType<Absolute<-12_345n | 12_345n>>(12_345n);
74+
expectType<Absolute<2 | 4 | -12_345n>>({} as 2 | 4 | 12_345n);
75+
expectType<Absolute<2 | 98_765n | 9.8 | 0b11n | 0o77 | 0xFF | 3e8>>({} as 2 | 98_765n | 9.8 | 0b11n | 0o77 | 0xFF | 3e8);
76+
expectType<Absolute<-2 | -98_765n | -9.8 | -0b11n | -0o77 | -0xFF | -3e8>>({} as 2 | 98_765n | 9.8 | 0b11n | 0o77 | 0xFF | 3e8);
77+
expectType<Absolute<-2 | -98_765n | 9.8 | 0b11n | 0o77 | -0xFF | 3e8>>({} as 2 | 98_765n | 9.8 | 0b11n | 0o77 | 0xFF | 3e8);
78+
79+
// 2. Literal and non-literal members
80+
expectType<Absolute<bigint | 100>>({} as bigint | 100);
81+
expectType<Absolute<bigint | -100>>({} as bigint | 100);
82+
expectType<Absolute<123_456_789n | number>>({} as 123_456_789n | number);
83+
expectType<Absolute<-123_456_789n | number>>({} as 123_456_789n | number);
84+
85+
// Boundary cases
86+
expectType<any>({} as Absolute<any>);
87+
expectType<never>({} as Absolute<never>);

test-d/internal/number-absolute.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)