Remove Empty Strings from an Array in JavaScript and TypeScript

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' ]
Command Prompt output showing an array of city names with empty strings removed by filter Boolean and by an explicit comparison
Five entries become three, and the original array is unchanged.
What you want to removeUse
Empty strings onlyvalues.filter(value => value !== "")
Empty strings, shortest formvalues.filter(Boolean)
Empty and whitespace-onlyvalues.filter(value => value.trim() !== "")
Empty, and trim what is leftvalues.map(v => v.trim()).filter(Boolean)
Empty, null and undefinedvalues.filter(v => v?.trim())
The same, keeping the type in TypeScriptvalues.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' ]
Command Prompt output showing that filter Boolean keeps a whitespace only string while trimming first removes it
The second line removes " ", "\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' ]
Command Prompt output showing filter Boolean removing zero false NaN null and undefined from a mixed array while an explicit filter keeps them
Note the string "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'.
Command Prompt showing TypeScript error TS2322 because filter Boolean returns an array that may still contain null or undefined
The values are gone; the type still says they might be there.

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' ]
Command Prompt output showing a TypeScript type predicate producing a string array so toUpperCase can be called on every item
Now it is a real 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:

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().