The TypeScript compiler is complaining because you’re trying to pass an argument to a function that doesn’t match the type the function expects. This happens when the shape or specific type of the data you’re providing doesn’t align with the function’s defined parameters.

Here’s a breakdown of the most common reasons for this error and how to fix them:

1. Mismatched Primitive Types

The most frequent culprit is passing a number where a string is expected, or vice-versa.

  • Diagnosis: Hover over the variable or expression you’re passing as an argument in your IDE. It will show you the inferred type. Then, check the function’s signature to see the expected type.
  • Fix: Explicitly convert the type. If you have a number myNum and need to pass it as a string:
    function processString(input: string) {
        console.log(input.toUpperCase());
    }
    
    let myNum: number = 123;
    // Incorrect: TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
    // processString(myNum);
    
    // Correct: Convert the number to a string
    processString(myNum.toString());
    
    If you have a string that should be a number, use parseInt() or parseFloat():
    function sum(a: number, b: number): number {
        return a + b;
    }
    
    let priceString: string = "19.99";
    // Incorrect: TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
    // sum(10, priceString);
    
    // Correct: Convert the string to a number
    sum(10, parseFloat(priceString));
    
  • Why it works: TypeScript enforces type safety. toString() guarantees the output is a string, and parseFloat() guarantees a number, satisfying the function’s signature.

2. Missing or Extra Properties in Object Literals

When passing an object to a function, the object must have at least the properties the function expects, with matching types.

  • Diagnosis: Examine the function signature’s parameter type. Compare it against the object literal you are providing.
  • Fix: Ensure all required properties are present and have the correct types. If the function expects an object with name: string and age: number:
    interface User {
        name: string;
        age: number;
    }
    
    function greetUser(user: User) {
        console.log(`Hello, ${user.name}! You are ${user.age} years old.`);
    }
    
    // Incorrect: Missing 'age' property
    // greetUser({ name: "Alice" });
    
    // Incorrect: 'age' is the wrong type
    // greetUser({ name: "Bob", age: "twenty" });
    
    // Correct: All properties present with correct types
    greetUser({ name: "Charlie", age: 30 });
    
  • Why it works: The object literal now conforms to the User interface, satisfying the user: User parameter type.

3. Union Types and Specificity

You might be passing a variable that could be one of several types (a union type), but the function expects a specific type within that union.

  • Diagnosis: Check the type of your variable and the expected parameter type. If your variable is string | number and the function expects string, you’ll get this error.
  • Fix: Narrow down the union type before passing it.
    function processOnlyStrings(input: string) {
        console.log(`Processing string: ${input}`);
    }
    
    let data: string | number = "hello";
    // Incorrect: TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'.
    // processOnlyStrings(data);
    
    // Correct: Check the type before passing
    if (typeof data === 'string') {
        processOnlyStrings(data);
    }
    
  • Why it works: The typeof data === 'string' check acts as a type guard, assuring TypeScript that data is indeed a string within that block, making it assignable to the string parameter.

4. null or undefined Being Passed to Non-Nullable Types

By default, null and undefined are not assignable to any type unless strictNullChecks is off or the type explicitly includes null or undefined in a union.

  • Diagnosis: Inspect the variable you are passing. If it could potentially be null or undefined, and the function parameter does not allow it (e.g., param: string instead of param: string | null), this error will occur.
  • Fix: Add checks to ensure the value is not null or undefined, or modify the function signature if null/undefined are valid inputs.
    function displayMessage(message: string) {
        console.log(message);
    }
    
    let userMessage: string | null = null; // Could be null
    
    // Incorrect: TS2345: Argument of type 'string | null' is not assignable to parameter of type 'string'.
    // displayMessage(userMessage);
    
    // Correct: Check for null
    if (userMessage !== null) {
        displayMessage(userMessage);
    }
    
    // Alternative Correct: If the function CAN accept null, modify its signature
    function displayOptionalMessage(message: string | null) {
        console.log(message ?? "No message provided");
    }
    displayOptionalMessage(userMessage); // This now works
    
  • Why it works: The check userMessage !== null ensures that only a valid string is passed. Alternatively, modifying the function signature to string | null explicitly tells TypeScript that null is an acceptable input.

5. Mismatched Function Types

You might be trying to pass a function as an argument, but its signature (parameters and return type) doesn’t match what the receiving function expects.

  • Diagnosis: Compare the type of the function you’re providing with the type expected by the parameter.
  • Fix: Adjust your function to match the required signature.
    function executeCallback(callback: (value: number) => void) {
        callback(42);
    }
    
    // Incorrect: Callback expects a number, but receives a string
    // executeCallback((val: string) => console.log(`Received: ${val}`));
    
    // Incorrect: Callback returns a string, but expects void (no return)
    // executeCallback((val: number) => `The number is ${val}`);
    
    // Correct: Callback matches the signature
    executeCallback((val: number) => {
        console.log(`Processing number: ${val}`);
    });
    
  • Why it works: The provided callback now precisely matches the (value: number) => void signature, fulfilling the executeCallback function’s requirement.

6. Generics and Type Arguments

When working with generic functions or classes, you might forget to provide the correct type argument, or the inferred type argument is not compatible.

  • Diagnosis: Look at the generic function call. If it’s myGenericFunc(arg), TypeScript might infer the type. If it’s myGenericFunc<SomeType>(arg), ensure SomeType is correct. Check the generic constraint.
  • Fix: Explicitly provide the type argument or ensure the inferred type is correct.
    function identity<T>(arg: T): T {
        return arg;
    }
    
    let output1 = identity("myString"); // T is inferred as string
    let output2 = identity(100);      // T is inferred as number
    
    function processStringOnly<T extends string>(arg: T): void { // Constraint: T must be a string
        console.log(arg.length);
    }
    
    // Incorrect: TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
    // processStringOnly(123);
    
    // Correct: Pass a string
    processStringOnly("hello");
    
    // Correct: Explicitly provide type argument if inference is tricky
    let numValue = 5;
    // Incorrect: TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
    // processStringOnly<number>(numValue);
    
    // Correct:
    processStringOnly<string>(numValue.toString());
    
  • Why it works: The <T extends string> constraint on processStringOnly enforces that only string types (or subtypes) can be passed. Providing numValue.toString() satisfies this constraint.

The next error you’ll likely encounter after fixing these is related to return types not matching, or perhaps a missing semicolon if you’re in a particularly strict linter configuration.

Want structured learning?

Take the full Typescript course →