Created
February 4, 2021 17:27
-
-
Save doasync/a274357eaeb116a0adcf4d96517afb14 to your computer and use it in GitHub Desktop.
Human format
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type ReadableConfig = { | |
separator?: string; | |
unit?: string; | |
formatFn?: (value: number) => string; | |
fractional?: boolean; | |
}; | |
// Sorted from big to small | |
// See: https://www.bipm.org/en/measurement-units | |
const si = [ | |
{ | |
factor: 10 ** 9, | |
prefix: 'G', | |
}, | |
{ | |
factor: 10 ** 6, | |
prefix: 'M', | |
}, | |
{ | |
factor: 10 ** 3, | |
prefix: 'k', | |
}, | |
]; | |
// eslint-disable-next-line @typescript-eslint/unbound-method | |
export const formatDefault = new Intl.NumberFormat('en-US', { | |
maximumFractionDigits: 1, | |
useGrouping: false, | |
}).format; | |
export const humanFormat = ( | |
value: number, | |
{ | |
unit = '', | |
separator = '', | |
formatFn = formatDefault, | |
fractional = false, | |
}: ReadableConfig = {} | |
): string => { | |
for (const { factor, prefix } of si) { | |
if (Math.trunc((value / factor) * 10 ** Number(fractional))) { | |
return `${formatFn(value / factor)}${separator}${prefix}${unit}`; | |
} | |
} | |
return `${Math.trunc(value)}${separator}${unit}`; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { humanFormat } from './human-format'; | |
const numbers = [ | |
-1_234_567_890_000, | |
-12_345_678_900, | |
-1_234_567.89, | |
-123_456_789, | |
-12_345.678, | |
-1234, | |
-123, | |
-12.345, | |
-1.234, | |
-1, | |
-0, | |
0, | |
0.123, | |
0.789, | |
0, | |
1, | |
1.234, | |
12.345, | |
123, | |
1234, | |
12_345.678, | |
1_234_567.89, | |
123_456_789, | |
12_345_678_900, | |
1_234_567_890_000, | |
]; | |
// eslint-disable-next-line @typescript-eslint/unbound-method | |
const formatFn = new Intl.NumberFormat('de-DE', { | |
maximumFractionDigits: 3, | |
}).format; | |
describe('humanFormat', () => { | |
it('works', () => { | |
const formatted = numbers.map((number) => humanFormat(number)); | |
expect(formatted).toEqual([ | |
'-1234.6G', | |
'-12.3G', | |
'-1.2M', | |
'-123.5M', | |
'-12.3k', | |
'-1.2k', | |
'-123', | |
'-12', | |
'-1', | |
'-1', | |
'0', | |
'0', | |
'0', | |
'0', | |
'0', | |
'1', | |
'1', | |
'12', | |
'123', | |
'1.2k', | |
'12.3k', | |
'1.2M', | |
'123.5M', | |
'12.3G', | |
'1234.6G', | |
]); | |
}); | |
it('support units', () => { | |
const formatted = humanFormat(1_234_567.89, { unit: 'b/s' }); | |
expect(formatted).toEqual('1.2Mb/s'); | |
}); | |
it('support separator', () => { | |
const formatted = humanFormat(1_234_567.89, { separator: ' ' }); | |
expect(formatted).toEqual('1.2 M'); | |
}); | |
it('support separator and unit', () => { | |
const formatted = humanFormat(12_345.678, { | |
unit: 'b/s', | |
separator: ' ', | |
}); | |
expect(formatted).toEqual('12.3 kb/s'); | |
}); | |
it('support separator and unit (without prefix)', () => { | |
const formatted = humanFormat(123, { | |
unit: 'b/s', | |
separator: ' ', | |
}); | |
expect(formatted).toEqual('123 b/s'); | |
}); | |
it('support formatFn', () => { | |
const formatted = humanFormat(1_234_567.89, { formatFn }); | |
expect(formatted).toEqual('1,235M'); | |
}); | |
it('support formatFn, separator and unit', () => { | |
const formatted = humanFormat(1_234_567.89, { | |
formatFn, | |
unit: 'b/s', | |
separator: ' ', | |
}); | |
expect(formatted).toEqual('1,235 Mb/s'); | |
}); | |
it('support useFraction', () => { | |
const formattedA = humanFormat(-1234, { | |
fractional: true, | |
}); | |
expect(formattedA).toEqual('-1.2k'); | |
const formattedB = humanFormat(876_543_210, { | |
fractional: true, | |
}); | |
expect(formattedB).toEqual('0.9G'); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment