When you need to split a string and get the last element in TypeScript, call split() and read the final item with at(-1). Add ?? "" because TypeScript types that item as string | undefined:
const last = "Boston,Chicago,Seattle".split(",").at(-1) ?? ""; // "Seattle"
I tested all of this on TypeScript 7.0.2 and Node.js v22.22.2, strict mode on. What you see under each example is the real console output.
Below I cover at(-1), the classic length - 1 index, pop(), the compiler errors you’re likely to hit, empty and trailing parts, and a faster way that skips the array entirely.
Split a string and get the last element with at(-1)
split() returns a string[], and at() accepts a negative index that counts back from the end. So at(-1) is the last item, at(-2) the one before it. The older parts[parts.length - 1] returns the same thing:
const cities: string = "Boston,Chicago,Denver,Austin,Seattle";
const parts = cities.split(",");
console.log("parts:", parts);
console.log("at(-1):", parts.at(-1));
console.log("length - 1:", parts[parts.length - 1]);
const path: string = "reports/2026/q3/sales-summary.pdf";
console.log("file name:", path.split("/").at(-1));
const url: string = "https://example.com/orders/2026/10/ORD-48213";
console.log("order id:", url.split("/").at(-1));
const fullName: string = "Mary Ellen Johnson";
console.log("last name:", fullName.split(" ").at(-1));
Output:
parts: [ 'Boston', 'Chicago', 'Denver', 'Austin', 'Seattle' ]
at(-1): Seattle
length - 1: Seattle
file name: sales-summary.pdf
order id: ORD-48213
last name: Johnson

split() plus at(-1) pattern pulls a city, a file name, an order ID and a last name.This is the pattern I reach for with file paths, URL slugs and CSV columns. If you need the whole array rather than just one piece, see how to convert a string to an array in TypeScript.
Get the last element with pop() (and why it changes the array)
pop() also returns the last element, but it removes it from the array. On a throwaway split() result that doesn’t matter. If you keep the array, it does:
const tags: string = "typescript,node,react";
const list = tags.split(",");
const last = list.pop();
console.log("pop():", last);
console.log("array after pop():", list);
const list2 = tags.split(",");
console.log("at(-1):", list2.at(-1));
console.log("array after at(-1):", list2);
console.log("one-liner:", tags.split(",").pop());
Output:
pop(): react
array after pop(): [ 'typescript', 'node' ]
at(-1): react
array after at(-1): [ 'typescript', 'node', 'react' ]
one-liner: react
After pop(), react is gone from list, while at(-1) left list2 alone. I’d use at(-1) unless you really want to remove the item. More ways to drop items are in removing an item from an array in TypeScript.
Why is the last element string | undefined in TypeScript?
Both at() and pop() can return undefined on an empty array, so their return type is string | undefined. Assigning that to a string fails in strict mode. With noUncheckedIndexedAccess on, plain indexing gets the same treatment:
const csvRow: string = "Austin,TX,78701,1249.99";
const parts = csvRow.split(",");
const price: string = parts.at(-1);
const zip: string = parts.pop();
const total: string = parts[parts.length - 1];
Output:
last_undefined.ts(4,7): error TS2322: Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
last_undefined.ts(5,7): error TS2322: Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.
last_undefined.ts(6,7): error TS2322: Type 'string | undefined' is not assignable to type 'string'.
Type 'undefined' is not assignable to type 'string'.

at(-1), pop() and, with noUncheckedIndexedAccess, parts[parts.length - 1].Without that flag, parts[parts.length - 1] compiles as string, even though it can be undefined at runtime. The fix is the same for all three: give TypeScript a fallback or check the value.
const csvRow: string = "Austin,TX,78701,1249.99";
// 1. Fall back to a default with ??
const price: string = csvRow.split(",").at(-1) ?? "";
console.log("price:", `$${Number(price).toFixed(2)}`);
// 2. A helper that always returns a string
function lastPart(text: string, separator: string | RegExp): string {
return text.split(separator).at(-1) ?? "";
}
console.log("state:", lastPart("Portland, Oregon", ", "));
console.log("extension:", lastPart("invoice-2026-10-16.csv", "."));
// 3. Handle "nothing there" explicitly
const last = "".split("").at(-1);
if (last === undefined) {
console.log("no parts to read");
}
Output:
price: $1249.99
state: Oregon
extension: csv
no parts to read
The lastPart() helper hides the ?? "" once, so callers always get a string. Once you have the text, converting a string to a number in TypeScript covers parsing values like the price safely.
You could also write at(-1)!, since split() with a non-empty separator always returns at least one item. I avoid it, because "".split("") returns an empty array and the ! would hide that.
Fix “Property ‘at’ does not exist on type ‘string[]'”
at() arrived in ES2022. If your tsconfig.json targets an older lib, the compiler doesn’t know about it:
const states: string = "Texas,Ohio,Oregon";
console.log(states.split(",").at(-1));
Output:
last_lib.ts(2,31): error TS2550: Property 'at' does not exist on type 'string[]'. Do you need to change your target library? Try changing the 'lib' compiler option to 'es2022' or later.

lib to es2022 or later.Set "lib": ["es2022", "dom"] (or newer) and check that your runtime supports it; Node.js 16.6+ and current browsers do. On an older target, use parts[parts.length - 1].
The same error type shows up for other methods in fixing TS2550 for includes().
Handle empty strings and trailing separators
Most surprises come from the input, not the method. A trailing comma gives you an empty last part, and an empty string still splits into one empty item:
const show = (label: string, value: unknown) => console.log(label.padEnd(30), JSON.stringify(value));
show('"a,b,c".split(",")', "a,b,c".split(",").at(-1));
show('"a,b,c,".split(",")', "a,b,c,".split(",").at(-1));
show('"Seattle".split(",")', "Seattle".split(",").at(-1));
show('"".split(",")', "".split(",").at(-1));
show('"".split("")', "".split("").at(-1));
const messy: string = " Boston , Chicago , Denver , ";
const clean = messy.split(",").map((s) => s.trim()).filter(Boolean);
show("trimmed + filtered", clean.at(-1));
const spaced: string = " Mary Ellen Johnson ";
show("split(/\\s+/) after trim()", spaced.trim().split(/\s+/).at(-1));
show("last two parts", "2026/10/16".split("/").slice(-2));
Output:
"a,b,c".split(",") "c"
"a,b,c,".split(",") ""
"Seattle".split(",") "Seattle"
"".split(",") ""
"".split("") undefined
trimmed + filtered "Denver"
split(/\s+/) after trim() "Johnson"
last two parts ["10","16"]

"".split("") returns undefined, and trim plus filter(Boolean) cleans it up.When the separator isn’t found, you get the whole string back, which is usually what you want. For messy user input, trim each part and use filter(Boolean) to drop blanks; filtering arrays in TypeScript explains that step.
Splitting on a regex like /\s+/ handles runs of spaces, and slice(-2) returns the last two parts as an array. For splitting the array itself into chunks, see how to split an array in TypeScript.
Get the last part without split(): lastIndexOf() and slice()
If you only want the last piece, you don’t need an array at all. Find the last separator with lastIndexOf() and take everything after it:
function lastSegment(text: string, separator: string): string {
const i = text.lastIndexOf(separator);
return i === -1 ? text : text.slice(i + separator.length);
}
console.log(lastSegment("reports/2026/q3/sales-summary.pdf", "/"));
console.log(lastSegment("Seattle", ","));
console.log(lastSegment("us::west::oregon", "::"));
const line = "2026-10-16,Austin,TX,Widget,12,1249.99";
function time(label: string, fn: () => string): void {
let out = "";
for (let i = 0; i < 100_000; i++) out = fn(); // warm-up
const start = performance.now();
for (let i = 0; i < 1_000_000; i++) out = fn();
console.log(`${label.padEnd(22)} ${out} ${(performance.now() - start).toFixed(1)} ms`);
}
time("split(',').at(-1)", () => line.split(",").at(-1) ?? "");
time("lastIndexOf + slice", () => lastSegment(line, ","));
Output:
sales-summary.pdf
Seattle
oregon
split(',').at(-1) 1249.99 32.3 ms
lastIndexOf + slice 1249.99 30.6 ms
Both approaches return the same values; your timings will vary. I’d only switch to lastIndexOf() in a hot loop over large files, because split().at(-1) reads more clearly for everyone else on the team.
The helper returns the whole string when the separator is missing, just like split(), and it handles multi-character separators like ::. Calling it per row works well with the forEach method on TypeScript arrays.
Which way should you get the last element?
| Approach | Returns | Use it when |
|---|---|---|
split(sep).at(-1) | string | undefined | Default choice on ES2022+ |
parts[parts.length - 1] | string (or | undefined with the flag) | Older targets |
split(sep).pop() | string | undefined | You want to remove the item too |
lastIndexOf() |