Skip to content

Typing on function behaves differently if as type, interface or on the function #43365

Closed

Description

@mmahalwy

Bug Report

No error:

type CustomType = { name: string };
interface MyFunc {
  (arg: string): CustomType;
}

const myFunc: MyFunc = (arg) => {
  return { name: arg, extraKey: 1234 };
};

No error:

type CustomType = { name: string }
type MyFunc = (arg: string) => CustomType;

const myFunc: MyFunc = (arg) => {
  return { name: arg, extraKey: 1234 };
};

Errors:

type CustomType = { name: string }

const myFunc = (arg: string): CustomType => {
  return { name: arg, extraKey: 1234 };
};

// error: Type '{ name: string; extraKey: number; }' is not assignable to type 'CustomType'.
//  Object literal may only specify known properties, and 'extraKey' does not exist in type 'CustomType'.

🔎 Search Terms

Function types not erroring when using type or interface.

🕗 Version & Regression Information

Version 4.2.3

Tested from version 3.3.3 to 4.2.3

⏯ Playground Link

N/A

Playground link with relevant code

💻 Code

See above

🙁 Actual behavior

Only the last example fails.

🙂 Expected behavior

All examples above should error. The function returns an object with incorrect keys.

Activity

  1. MartinJohns commented on Mar 25, 2021

    @MartinJohns
    Contributor

    This is working as intended. In your no error versions you don't specify a return type for your functions, so the return type is inferred. Because the return type is inferree based on your returned value you don't get any excess properties. Then the compiler checks if your value (the function) is compatible with the annotated type of your variable (MyFunc).

  2. mmahalwy commented on Mar 25, 2021

    @mmahalwy
    Author

    I may have missed this Martin Johns (@MartinJohns). For this example, why is the return type inferred? I thought I set it explicitly as CustomType. See:

    type CustomType = { name: string }
    type MyFunc = (arg: string) => CustomType;
    
    const myFunc: MyFunc = (arg) => {
      return { name: arg, extraKey: 1234 };
    };
  3. MartinJohns commented on Mar 25, 2021

    @MartinJohns
    Contributor

    Because your anonymous arrow function has no type annotation for the return type:

    // No return type annotation
    (arg) => { return { name: arg, extraKey: 1234 }; }
    
    // With return type annotation
    (arg): { name: string } => { return { name: arg, extraKey: 1234 }; }
    

    Keep in mind that additional properties are legal in TypeScript. The excess property checks feature is often called "more of a linter feature" by the TypeScript team.

  4. mmahalwy commented on Mar 26, 2021

    @mmahalwy
    Author

    Right, I understand that example Martin Johns (@MartinJohns) but since I am setting the type on the function constant, I'd expect it to adhere to the return type annotation:

    type MyFunc = (arg: string) => CustomType;
    const myFunc: MyFunc;
  5. RyanCavanaugh commented on Mar 26, 2021

    @RyanCavanaugh
    Member

    See also #40311 which attempts to change this

  6. mmahalwy commented on Mar 26, 2021

    @mmahalwy
    Author

    Ryan Cavanaugh (@RyanCavanaugh) thanks for linking that. Would LOVE to see that PR merged 🙏

  7. typescript-bot commented on Mar 28, 2021

    @typescript-bot
    Contributor

    This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  8. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions