Skip to content

Function return type with array #33158

Closed
Closed

Description

TypeScript Version: 3.6.2

Search Terms:
map\array\return type

Code

const fetchCustomVariables = (): { name?: string; type?: string }[] => {
    const variableList: { name?: string; type: string }[] = [];
    return variableList.map(v => ({ nasme: v.name, type: v.type }));
};

NotificationsForm 2019-08-30 13 12 07
NotificationsForm 2019-08-30 13 14 15

Expected behavior:
Typescript complaints that array of objects generated by map doesn't match function return type.

Actual behavior:
Typescript doesn't complaint that array of objects generated by map doesn't match function return type.

Playground Link:
http://www.typescriptlang.org/play/#code/PTAEGUAsHsFcBsAmoDG0C2AHeBDAlgHYBQaBAzgC6gBmAphSpAMKyUYBqOATnjgEbxaZUAF5QACgCUALlABvUARzpaAflmUeBAOYBuUBQCemNRopbtoAL4BtALqiAfPKKg3qaOSoA3brwG0ADJ4lLIKSirqoJqEegbGtGYW1vaioPa6ru5c9LBcBKC+PPyCwZQAdOg4mOLeThLhOGQqst7lEbQANPEmreVGJtaSkplWmUQgoACCwpC0OSSelDT0jCxs6JzFAWQATGlSYYrKptHmsfoDpzE61vVyWW6ky0X+pSEURx1RN3FXSbEUg4xBlHqAchQ8gVGs1EqAAOQARnh3X+CN28LGRCxQA

Related Issues:
No

Activity

  1. AnyhowStep commented on Aug 30, 2019

    @AnyhowStep
    Contributor
    variableList.map((v) : { name?: string; type: string } => (
      { nasme: v.name, type: v.type }
    ));
  2. AnyhowStep commented on Aug 30, 2019

    @AnyhowStep
    Contributor

    You're running into this thing called excess property checks for object literals. It isn't applied on non-object literals.

    Without the explicit return type annotation on your .map() callback function, basically anything is allowed.

    Then, the result of .map() is not an object literal. So, it doesn't perform excess property checks and it allows nasme, the excess property.

  3. deser commented on Aug 30, 2019

    @deser
    Author

    Yes I saw that, but why typescript can't guess the type? And actually, seems, it already guesses it:
    image

  4. deser commented on Aug 30, 2019

    @deser
    Author

    And... map kind of already knows the type, it knows what array it iterates (not any). Why do I need to repeat that type for map explicitly again?

  5. AnyhowStep commented on Aug 30, 2019

    @AnyhowStep
    Contributor

    It knows the type. It just isn't applying the excess property checks because it wasn't made to do so.
    It's intentional.


    One of these may help,

    #28464 (comment)

    #32537

    #7481

    Also, try looking up "excess property check" and "object literal".
    It might turn up other stuff that explains the motivation for the current behaviour.

    Might also include other workarounds you might find more agreeable

  6. fatcerberus commented on Aug 30, 2019

    @fatcerberus

    What I believe happens here is that

    1. TS infers the type of the lambda expression v => ({ ... }). Because there's no explicit type annotation on the lambda, it simply infers a structural type based on whatever it actually returns. This is right because map allows you to output anything you want - there's no basis for it to infer any specific contract on the return type at this point.
    2. The object literal has now been fully accounted for, so its "freshness" flag is removed.
    3. TS asks if the function is usable with map. v (the argument) is already the correct type as determined by contextual typing and the return type can be anything at all, so yes, it's fine.
    4. Excess property checks now don't apply because the object literal(s) involved are no longer fresh.
      It simply asks whether { nasme: string | undefined, type: string }[] is structurally compatible with the return type of fetchCustomVariables, and it is.

    If you want the excess property checks in the lambda, annotate its return type:

    (v): ReturnType => value
  7. deser commented on Sep 6, 2019

    @deser
    Author

    Excess property checks now don't apply because the object literal(s) involved are no longer fresh.
    It simply asks whether { nasme: string | undefined, type: string }[] is structurally compatible with the return type of fetchCustomVariables, and it is.

    But typescript as far as I understood already infers return type of callback. It knows exactly what map will return.
    I mean it's quite possible to me in such simple cases (when all entities of map will be definitely of the same type) to not return any from map, but infer type and return correct type

  8. deser commented on Sep 6, 2019

    @deser
    Author

    Even if types are different depending on conditions, it's quite possible to return union type... :)

  9. thw0rted commented on Sep 9, 2020

    @thw0rted

    It looks like #40311 fixes this. Consider

    [1,2,3].map<{a:1}>(x => ({a:1, b:2}));

    We want the excess property b to be flagged.

    Current (v4.0.2) Playground -- no error

    PR Playground -- gives "may only specify known properties" error. 🎉 🎉 🎉

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

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions