Reputation: 46527
I have a function below that takes in numeric value and parses it into currency values like 11k, 1m etc... It achieves the task, but I am receiving ts error on this line:
const [match] = `${value / divider}`.match(regx);
Error
Type 'null' must have a 'Symbol.iterator' method that returns an iterator.ts(2488)
Full code
export function getCurrencyValue(value: number) {
const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = new RegExp('^-?\\d+(?:.\\d{0,1})?');
let formatedValue = '';
ranges.forEach(range => {
const { divider, suffix } = range;
if (value >= divider) {
const [match] = `${value / divider}`.match(regx);
if (match) {
formatedValue = `${match}${suffix}`;
}
}
});
return formatedValue || value;
}
Upvotes: 1
Views: 6296
Reputation: 1075337
You can't destructure null
, so
const [match] = `${value / divider}`.match(regx);
...would throw if there were no match, since match
returns null
when there's no match. You'll need to split that into two statements, or use the || []
trick or similar. Looking at your full code, it doesn't seem like destructuring helps here (because of the possible null
), simply:
const match = `${value / divider}`.match(regx);
if (match) {
formatedValue = `${match[0]}${suffix}`;
}
The reason the error message says what it says is that the kind of destructuring you're doing (using []
) relies on getting an iterator from the thing you're destructuring (the result of match
). You get an iterator from something by using its Symbol.iterator
method:
const it = `${value / divider}`.match(regx)[Symbol.iterator]();
Since one of the things match
can return is null
, and null
doesn't (and can't) have a Symbol.iterator
property, TypeScript complains about it.
Side note: forEach
doesn't seem like the right tool here, since you want to stop the first time you get a match. Right now, you'll write to formattedValue
for the 1e6
range, but then overwrite it with the result of formatting the 1e3
range.
for-of
would be a good choice:
export function getCurrencyValue(value: number) {
const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = new RegExp('^-?\\d+(?:.\\d{0,1})?');
for (const { divider, suffix } of ranges) {
if (value >= divider) {
const match = `${value / divider}`.match(regx);
if (match) {
return `${match[0]}${suffix}`;
}
}
});
return String(value); // Presumably you always want it to be a string
}
I'd also probably use literal regular expression syntax for clarity (don't have to double-escape backslashes), and move both the ranges
and regx
outside the function so they aren't re-created every time (since this is in a module, and separately since the regex doesn't have the g
or y
flags):
const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = /^-?\d+(?:.\d{0,1})?/;
export function getCurrencyValue(value: number) {
for (const { divider, suffix } of ranges) {
if (value >= divider) {
const match = `${value / divider}`.match(regx);
if (match) {
return `${match[0]}${suffix}`;
}
}
});
return String(value); // Presumably you always want it to be a string
}
You've said you're not allowed to use for-of
in your environment because you're transpiling to ES5 and not allowed to rely on regenerator-runtime. So instead of forEach
, you'd want some
:
const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = /^-?\d+(?:.\d{0,1})?/;
export function getCurrencyValue(value: number) {
let formattedValue = String(value); // Presumably you want it to always be a string
// Not allowed to use for-of, and the rule saying not to use it also doesn't like `for` loops, so...
ranges.some(({ divider, suffix }) => {
if (value >= divider) {
const match = `${value / divider}`.match(regx);
if (match) {
formattedValue = `${match[0]}${suffix}`;
return true;
}
}
return false;
});
return formattedValue;
}
Or with reduce
:
const ranges = [{ divider: 1e6, suffix: 'm' }, { divider: 1e3, suffix: 'k' }];
const regx = /^-?\d+(?:.\d{0,1})?/;
export function getCurrencyValue(value: number) {
// Not allowed to use for-of, and the rule saying not to use it also doesn't like `for` loops, so...
return ranges.reduce((formattedValue, { divider, suffix }) => {
if (value >= divider) {
const match = `${value / divider}`.match(regx);
if (match) {
formattedValue = `${match[0]}${suffix}`;
}
}
return formattedValue;
}, String(value)); // Presumably you always want it to be a string
}
Upvotes: 8