The TypeScript compiler tsc failed because it encountered code that wasn’t a valid declaration or statement at the top level of a module or script.

This usually means you’ve accidentally put something that belongs inside a function or a block, or you’ve got a syntax error that’s confusing the parser.

Common Causes and Fixes:

  1. Unassigned Variable Declaration: You declared a variable but didn’t initialize it or use it in a statement.

    • Diagnosis: Look for lines that start with let or const followed by a variable name and a semicolon, with nothing else on the line.
      let myVariable; // This can cause TS1128 if it's the only thing on the line in certain contexts
      
    • Fix: Either assign a value or use it in a statement.
      let myVariable: string; // Add a type annotation if not initializing
      // OR
      let myVariable = "initial value"; // Initialize it
      // OR
      console.log(myVariable); // Use it in a statement
      
    • Why it works: TypeScript expects top-level declarations to be either fully declared (with type or value) or part of an executable statement. A bare let variable; can be ambiguous.
  2. Missing Semicolon After a Statement: A statement is immediately followed by another declaration or a syntax error, and the first statement is missing its terminating semicolon.

    • Diagnosis: Check lines immediately preceding the error. If a statement seems complete but is followed by something unexpected, a missing semicolon is likely.
      const config = { timeout: 5000 }
      let apiUrl: string; // TS1128 might point here
      
    • Fix: Add a semicolon to the end of the preceding statement.
      const config = { timeout: 5000 }; // Added semicolon
      let apiUrl: string;
      
    • Why it works: Semicolons explicitly delimit statements. Without it, tsc might parse the next line as a continuation of the previous one, leading to confusion.
  3. Invalid Expression as a Statement: You’ve placed an expression on its own line where tsc expects a declaration or a statement that has side effects.

    • Diagnosis: Look for lines containing only an expression that doesn’t produce a side effect (like a function call, assignment, or new expression).
      "This is just a string literal"; // TS1128
      
    • Fix: Either assign the expression to a variable, use it in a valid statement, or remove it if it’s accidental.
      const message = "This is just a string literal";
      // OR
      console.log("This is just a string literal");
      
    • Why it works: A standalone string literal isn’t a valid statement on its own. It needs to be part of an assignment or a function call to be processed.
  4. Incorrect Placement of Type Annotations: A type annotation is used where a value or declaration is expected, or it’s misplaced within a declaration.

    • Diagnosis: Examine declarations where types are applied.
      let myFunction: () => void = () => { /* ... */ };
      myFunction: string; // TS1128, this looks like a type annotation on a variable but isn't in a declaration context
      
    • Fix: Ensure type annotations are correctly part of a declaration or assignment.
      let myFunction: () => void = () => { /* ... */ };
      let anotherVariable: string; // Correct declaration
      
    • Why it works: Type annotations are syntax specific to declarations (let x: type;) or assignments (let x: type = value;). Using them out of context breaks the parser.
  5. Accidental Export of a Type Without a Value: In some module systems, exporting a type alias or interface without a corresponding value export can lead to this error.

    • Diagnosis: Check export statements. If you’re exporting a type alias or interface and nothing else on that line, it might be the culprit.
      export type MyType = { prop: string }; // In some strict module configurations or older TS versions
      
    • Fix: Ensure there’s a value export or a valid declaration associated with the export.
      export type MyType = { prop: string };
      export const myTypeValue: MyType = { prop: "hello" };
      // OR
      export interface MyInterface { prop: string }
      
    • Why it works: The compiler expects export to apply to declarations that can be instantiated or have runtime presence, not just purely static type constructs without accompanying value exports.
  6. Stray Characters or Syntax Errors: A simple typo, an unclosed bracket, or an unexpected character can confuse the parser into thinking it’s found something that isn’t a valid statement or declaration.

    • Diagnosis: Look very closely at the line indicated by the error and the lines immediately before and after it for any unusual characters, misplaced punctuation, or incomplete constructs.
      const data = {
        user: "Alice"
        // Missing comma here, or a stray character after "Alice"
      }
      let processedData; // TS1128 might point here due to the error in the object above
      
    • Fix: Correct the underlying syntax error. In the example above, adding a comma to the object literal.
      const data = {
        user: "Alice", // Added comma
      }
      let processedData;
      
    • Why it works: The compiler works by parsing code into an Abstract Syntax Tree (AST). A syntax error prevents the creation of a valid AST node at that position, causing tsc to report an unexpected token where it expects a declaration or statement.

After fixing these, you might encounter TS2304: Cannot find name '...', which means you’ve fixed the syntax but now need to ensure all your references point to actual declared variables or types.

Want structured learning?

Take the full Typescript course →