TS1002Syntax Error
Since TS 1.0

Fix TS1002: Unterminated String Literal

Learn why TypeScript throws TS1002 when a string literal is never closed, and how to fix it with escaping, template literals, or concatenation.

error TS1002: Unterminated string literal

What This Error Means

TS1002 means the TypeScript scanner found a string that was opened but never closed. You started a literal with ' or ", and the line ended — or the file ended — before a matching quote showed up.

This happens before type checking, before parsing even completes. The scanner turns your source text into tokens, and ordinary string literals are not allowed to contain a raw line break. When it reaches the newline with the string still open, it stops the token there and reports TS1002 at that position. Nothing in the file can be type-checked until the quote is balanced again.

The behavior has been the same since TypeScript 1.0 and there is no compiler flag involved — strict, target and module make no difference at all.

// The general shape of the error:
const emailBody = '<p>Hello Dana,
//                ~~~~~~~~~~~~~~~ Error: Unterminated string literal.

Because the scanner is now out of sync with your code, the errors printed after a TS1002 are usually meaningless. Fix the first one and re-run the compiler before you read the rest.

Common Causes

1. Text That Spans Several Lines

Pasting an HTML fragment, an SQL query, or an email body into quotes is the classic trigger. Single and double quotes cannot contain a real line break, so the string dies at the end of the first line.

// ❌ Broken
const emailBody = '<p>Hello Dana,
  your order shipped today.</p>'
//                ~~~~~~~~~~~~~~~ Error: Unterminated string literal.
// plus TS1434 / TS1003 / TS1161 on line 2 — all cascade noise
// ✅ Fixed — a template literal is allowed to contain line breaks
const emailBody = `<p>Hello Dana,
  your order shipped today.</p>`

Template literals keep the text readable and preserve the newline. If you need to stay on one line, '<p>Hello Dana,\n your order shipped today.</p>' produces the same string.

2. An Unescaped Quote Inside the String

An apostrophe inside a single-quoted string closes it early. The rest of the line then opens a second string that never gets closed — which is the one the compiler actually complains about.

// ❌ Broken
const orderTitle = 'Customer's pending orders'
//                 ~~~~~~~~~~~ this string ends here...
//                            ~~~~~~~~~~~~~~~~~ ...and this one is never closed
// Error: Unterminated string literal.
// ✅ Fixed — switch the outer quotes so the apostrophe is just a character
const orderTitle = "Customer's pending orders"
 
// ✅ Also fine — escape the apostrophe
const orderTitleAlt = 'Customer\'s pending orders'

Note where the reported column lands: on the second half of the line, several characters after the real mistake. Read the whole line, not just the caret.

3. A Trailing Backslash Before the Closing Quote

Windows paths and generated config values often end in a backslash. A backslash escapes the character that follows it, so a trailing one escapes your closing quote and the string runs on.

// ❌ Broken
const logDirectory = 'C:\Users\deploy\logs\'
//                                        ~~ the backslash escapes the quote
// Error: Unterminated string literal.
// ✅ Fixed — escape the backslashes themselves
const logDirectory = 'C:\\Users\\deploy\\logs\\'
 
// ✅ Simpler — forward slashes work on Windows too
const logDirectoryPosix = 'C:/Users/deploy/logs/'

This one bites hardest in .ts config files where a value was copied out of JSON or produced by a code generator — the original text was fine, the escaping was lost in transit.

How to Fix It

  1. Go to the first TS1002 and only that one. Later errors on the following lines (TS1161: Unterminated regular expression literal, TS1003, TS1005) are the scanner recovering, not separate bugs. They vanish when the quote is fixed.

  2. Decide whether the string is meant to span lines. If it is, use a template literal:

    const receiptHeader = `Order #4821
    Shipped to: Dana Ruiz`

    If the line break was accidental, just pull the text back onto one line.

  3. Escape or swap the quote character. For an apostrophe inside text, prefer double quotes on the outside — "Customer's orders" reads better than 'Customer\'s orders'. For a literal backslash, double it.

  4. Prefer an array join over long concatenation. When you are assembling many lines, this stays readable and cannot lose a quote in the middle:

    const receiptLines = [
      'Order #4821',
      'Shipped to: Dana Ruiz',
      'Total: $128.40',
    ].join('\n')
  5. Don't try to silence it. TS1002 is a scanner error, so as any, @ts-ignore and turning off strict flags do nothing — the comment itself may not even be tokenized correctly. The quote has to be fixed.

  6. Let your editor catch it next time. Syntax highlighting turns the entire rest of the file into "string" colouring the moment a quote goes unmatched — that colour change is the fastest way to spot the opening quote. Formatting on save (Prettier) also fails loudly on an unterminated string instead of committing it.

FAQ

What causes TypeScript error TS1002?

TS1002 is raised by the scanner when a '…' or "…" literal hits a line break or the end of the file before its closing quote. In practice it comes from one of three things: text that was meant to span multiple lines, an apostrophe or quote character inside the string that was not escaped, or a trailing backslash that accidentally escaped the closing quote.

It is not affected by any compiler option. The rule that ordinary string literals may not contain raw line breaks comes from JavaScript itself, and it has been enforced since TypeScript 1.0.

How do I write a multi-line string in TypeScript?

Use a template literal — backticks instead of quotes. It is the only string form that may contain real line breaks, and it keeps the text laid out the way you wrote it:

const query = `SELECT id, total
FROM orders
WHERE status = 'shipped'`

Two alternatives work when you want the value on one line in the source: put \n where the break belongs, or build an array of lines and call .join('\n'). Both produce exactly the same string, so pick whichever reads better in context.

Why do I get extra errors like TS1161 after TS1002?

Because the scanner is now misaligned. It thinks the rest of your line is still inside a string, so the next quote it meets is read as a closing quote and everything after that is interpreted as code that makes no sense. A multi-line single-quoted string typically reports TS1002 on the first line and then TS1434, TS1003 and TS1161 on the second.

None of those are real problems. Fix the unterminated string, save, and re-run the compiler — the follow-up errors disappear together. As a general habit with syntax-level errors, always fix the earliest reported error first and re-check before reading further down the list.

Related Errors

Practice This

Browse all TypeScript practice challenges to keep sharpening your type-level skills.

Share this reference

Become a TypeScript Pro

Track your progress through 100+ hands-on challenges. Free, sign in with GitHub.

Or start solving right away: explore all TypeScript challenges