To remove empty strings from an array, filter them out: values.filter(Boolean) is the short version and values.filter(value => value !== "") is the explicit one. Both return a new array and leave the original alone. If the array also contains strings that are only spaces or tabs, trim first: values.filter(value => value.trim() !== ""). The code is the same in JavaScript and TypeScript; the one extra thing TypeScript needs is a type predicate, so the result is typed string[] rather than keeping null and undefined in the type. All of it is below, run and with the real output.
Every example was run with Node.js v22.22.2 and TypeScript 5.2.2 in the Windows Command Prompt. The JavaScript files run straight through node; the TypeScript ones are compiled with tsc first. Reference: Array.prototype.filter() on MDN.
Remove empty strings from an array
An empty string is falsy, so passing the Boolean function as the predicate keeps everything else. For an array that holds only strings, this is safe and is the version you will see most often:
const cities = ["Austin", "", "Denver", "", "Seattle"];
console.log(cities.filter(Boolean)); // shortest way
console.log(cities.filter(city => city !== "")); // the explicit test
console.log(cities.length, "->", cities.filter(Boolean).length);
console.log(cities); // the original is untouched
Output:
[ 'Austin', 'Denver', 'Seattle' ]
[ 'Austin', 'Denver', 'Seattle' ]
5 -> 3
[ 'Austin', '', 'Denver', '', 'Seattle' ]
| What you want to remove | Use |
|---|---|
| Empty strings only | values.filter(value => value !== "") |
| Empty strings, shortest form | values.filter(Boolean) |
| Empty and whitespace-only | values.filter(value => value.trim() !== "") |
| Empty, and trim what is left | values.map(v => v.trim()).filter(Boolean) |
Empty, null and undefined | values.filter(v => v?.trim()) |
| The same, keeping the type in TypeScript | values.filter((v): v is string => ...) |
Strings that are only spaces
" " is not an empty string: it has three characters in it, so it is truthy and survives filter(Boolean). Trim before you test, or trim and filter in one pass when you want the surviving values cleaned up too:
const input = ["Austin", "", " ", "Denver\t", "\n", "Seattle"];
// filter(Boolean) keeps " " because a space is not an empty string
console.log(input.filter(Boolean));
// trim() first, and the whitespace-only entries go too
console.log(input.filter(value => value.trim() !== ""));
// clean and filter in one pass
console.log(input.map(value => value.trim()).filter(Boolean));
Output:
[ 'Austin', ' ', 'Denver\t', '\n', 'Seattle' ]
[ 'Austin', 'Denver\t', 'Seattle' ]
[ 'Austin', 'Denver', 'Seattle' ]
" ", "\t" and "\n" as well.Where the empty strings come from: split()
Most empty strings in an array are made by split(). Two separators in a row produce an empty string between them, and a trailing separator produces one at the end. Splitting an empty string is the odd case: it gives you a one-item array holding an empty string, which is why the last line still needs the filter to end up empty. Cleaning a comma-separated list is the classic use:
const line = "Austin,,Denver, ,Seattle,";
console.log(line.split(",")); // this is where empty strings come from
console.log(line.split(",").map(v => v.trim()).filter(Boolean));
const tags = " react ,, typescript , ";
console.log(tags.split(",").map(t => t.trim()).filter(Boolean));
console.log("no separators".split(",").filter(Boolean));
console.log("".split(",").filter(Boolean)); // an empty string splits into [""]
Output:
[ 'Austin', '', 'Denver', ' ', 'Seattle', '' ]
[ 'Austin', 'Denver', 'Seattle' ]
[ 'react', 'typescript' ]
[ 'no separators' ]
[]
The pattern split then map(trim) then filter(Boolean) is worth remembering as a unit: it turns messy user input into a clean list in one line.
filter(Boolean) removes more than empty strings
On a mixed array, Boolean throws out every falsy value: 0, false, NaN, null and undefined go along with "". If 0 is real data, that line quietly loses it. Test explicitly when the array holds more than strings, and see filtering arrays for more on choosing a predicate:
const values = ["Austin", "", 0, "Denver", null, false, NaN, "0", undefined];
console.log(values.filter(Boolean)); // drops every falsy value, not only ""
console.log(values.filter(value => value !== "")); // keeps 0, null, false and NaN
// keep real values, drop empty strings and nothing else
console.log(values.filter(value => value !== "" && value !== null && value !== undefined));
Output:
[ 'Austin', 'Denver', '0' ]
[
'Austin', 0,
'Denver', null,
false, NaN,
'0', undefined
]
[ 'Austin', 0, 'Denver', false, NaN, '0' ]
"0" survives: it is a non-empty string, so it is truthy.Arrays of objects
With objects you either drop whole records that are missing a value, or keep the record and strip its empty fields. The second one is handy before sending a form payload to an API, and it pairs with filtering an array of objects:
const rows = [
{ id: "ORD-1001", customer: "Emma Johnson", note: "" },
{ id: "ORD-1002", customer: "", note: "call back" },
{ id: "ORD-1003", customer: "Olivia Davis", note: " " },
];
// drop the records whose customer name is missing
console.log(rows.filter(row => row.customer.trim() !== "").map(r => r.id));
// or keep every record and drop the empty fields inside it
const clean = rows.map(row =>
Object.fromEntries(Object.entries(row).filter(([, value]) => String(value).trim() !== ""))
);
console.log(clean);
Output:
[ 'ORD-1001', 'ORD-1003' ]
[
{ id: 'ORD-1001', customer: 'Emma Johnson' },
{ id: 'ORD-1002', note: 'call back' },
{ id: 'ORD-1003', customer: 'Olivia Davis' }
]
Cleaning rows from a file or a textarea
The same three calls scale up to a whole CSV or a pasted block of text: split into lines, clean each line, then drop the lines that are left with nothing. Counting what you removed gives you the message to show the user:
const csv = `Austin,TX,
,,
Denver, CO ,USA
`;
// clean every cell, then drop the rows that end up with nothing in them
const rows = csv
.split("\n")
.map(line => line.split(",").map(cell => cell.trim()).filter(Boolean))
.filter(row => row.length > 0);
console.log(rows);
// keep a count of what was thrown away, for a validation message
const cells = ["Austin", "", "Denver", " ", "Seattle"];
const kept = cells.filter(cell => cell.trim() !== "");
console.log(`kept ${kept.length} of ${cells.length}, removed ${cells.length - kept.length} empty cells`);
Output:
[ [ 'Austin', 'TX' ], [ 'Denver', 'CO', 'USA' ] ]
kept 3 of 5, removed 2 empty cells
TypeScript: keeping the result typed as string[]
Here is the one place where TypeScript needs more than the JavaScript version. Filtering does remove the empty values at runtime, but on TypeScript 5.2 the type does not change, so the result cannot be assigned to string[]:
const raw: (string | null | undefined)[] = ["Austin", "", null, "Denver", undefined];
const cities: string[] = raw.filter(Boolean); // still (string | null | undefined)[]
console.log(cities);
tsc output:
remove_empty_types.ts(3,7): error TS2322: Type '(string | null | undefined)[]' is not assignable to type 'string[]'.
Type 'string | null | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
A type predicate, value is string, fixes it, and wrapping it in a small isFilled helper means you write it once. TypeScript 5.5 and later infer this from the function body. The same approach removes undefined values from an array:
const raw: (string | null | undefined)[] = ["Austin", "", null, "Denver", undefined, " "];
// a type predicate keeps the result typed as string[]
const isFilled = (value: string | null | undefined): value is string =>
typeof value === "string" && value.trim() !== "";
const cities: string[] = raw.filter(isFilled);
console.log(cities, cities.map(city => city.toUpperCase()));
// a reusable version for any array of optional strings
function withoutEmpty(values: readonly (string | null | undefined)[]): string[] {
return values.filter(isFilled).map(value => value.trim());
}
console.log(withoutEmpty([" Austin ", "", null, " Denver"]));
Output:
[ 'Austin', 'Denver' ] [ 'AUSTIN', 'DENVER' ]
[ 'Austin', 'Denver' ]
string[], so toUpperCase() compiles.Removing them in place
filter() builds a new array, which is what you usually want. If you must edit the existing array, loop backwards: removing an element shifts everything after it down one position, so a forwards loop skips the next entry. The second half of this example shows that skip happening, and removing items from an array covers the general rule:
const cities: string[] = ["Austin", "", "Denver", "", "Seattle"];
// removing in place: walk backwards so the shifting indexes do not skip anything
for (let i = cities.length - 1; i >= 0; i--) {
if (cities[i].trim() === "") cities.splice(i, 1);
}
console.log(cities, cities.length);
// the forwards version misses the second empty string
const broken: string[] = ["Austin", "", "", "Denver"];
broken.forEach((value, i) => { if (value === "") broken.splice(i, 1); });
console.log(broken);
Output:
[ 'Austin', 'Denver', 'Seattle' ] 3
[ 'Austin', '', 'Denver' ]
To empty an array completely rather than clean it, that is a different job: see clearing an array while keeping its type.
More array-cleaning guides worth reading:
- Remove undefined values from an array
- Remove duplicates from an array
- Check if an array is null or empty
- Filter arrays in TypeScript
- Loop through an array
Frequently asked questions
How do I remove empty strings from an array in JavaScript?
Use values.filter(Boolean), or values.filter(v => v !== "") if you want the test spelled out. Both return a new array.
How do I remove empty and whitespace-only strings?
Trim before testing: values.filter(v => v.trim() !== ""). filter(Boolean) keeps " ", because spaces are characters.
Is filter(Boolean) safe to use?
On an array of strings, yes. On a mixed array it also drops 0, false, NaN, null and undefined.
Why does my array have empty strings after split()?
Two separators in a row, or a trailing separator, each produce one. "a,,b,".split(",") gives four items, two of them empty.
Does filter() change the original array?
No. It returns a new array, so keep the result: values = values.filter(Boolean) if you want the variable updated.
How do I remove empty strings and keep the TypeScript type?
Use a type predicate: values.filter((v): v is string => v.trim() !== ""). TypeScript 5.5 and later work it out for you.
How do I remove empty strings from an array of objects?
Filter on the field: rows.filter(row => row.name.trim() !== ""), or rebuild each object without its empty fields using Object.entries().
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn