5

I'm looking at facebook's immutable library and their typescript bindings.

If I have this code:

const list: User[] = ...;
list.map(user => ...)

The type of the lambda parameter user is correctly User.

However, if I import immutable's List and wrap my array:

import {Map, List} from "immutable";
List(list).map(user => ...)

Now, and it's baffling to me, the lambda parameter user is inferred to be User | undefined. Even changing the call to List<User>(list) does not help.

Looking at the .d.ts for the library, the definition is:

export function List<T>(array: Array<T>): List<T>;

So I don't understand what is going on here?

Emmanuel Touzery
  • 9,008
  • 3
  • 65
  • 81

1 Answers1

4

The reason for this is written in the What's new in TypeScript 2.0 in the Optional parameters and properties part:

Optional parameters and properties automatically have undefined added to their types, even when their type annotations don't specifically include undefined. For example, the following two types are identical:

// Compiled with --strictNullChecks
type T1 = (x?: number) => string;              // x has type number | undefined
type T2 = (x?: number | undefined) => string;  // x has type number | undefined

Edit

The definition file for immutable.js changed, now if you look at the signature of the map method it looks like this:

map<M>(
    mapper: (value: V, key: K, iter: /*this*/Iterable<K, V>) => M,
    context?: any
): /*this*/Iterable<K, M>;

But if you go a commit before that it looks like this:

map<M>(
    mapper: (value?: V, key?: K, iter?: /*this*/Iterable<K, V>) => M,
    context?: any
): /*this*/Iterable<K, M>;

And here the value is optional.

If you update the definition file it will be fixed.

Nitzan Tomer
  • 155,636
  • 47
  • 315
  • 299
  • i don't think the first parameter of the map callback is optional. The signature is this one or similar I think => `map(mapper: (value: V, key: K, iter: this) => M,context?: any): /*this*/Iterable; ` – Emmanuel Touzery Dec 09 '16 at 23:17
  • I really have that old definition on my disk it seems! Although I just installed it. I installed through `npm install @types/immutable --save` and got `"@types/immutable": "3.8.6"`. Is there a better way? – Emmanuel Touzery Dec 09 '16 at 23:26
  • (I also have issues with the tsmonad type definition which seems to conflict with node over the variable 'module'. I thought installing type definitions through npm & @types was the right way now? – Emmanuel Touzery Dec 09 '16 at 23:40
  • 1
    The file in [@types/immutable](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/types-2.0/immutable/index.d.ts) is the latest one (with the params as not optional), but the `immutable.js` library comes with its' own `.d.ts` file and the compiler might be using that instead of the `@types/immutable`. Check what you have there, maybe you need to update your `immutable.js` lib. – Nitzan Tomer Dec 09 '16 at 23:40
  • i have "immutable": "3.8.1" in my package.json, seems to be the latest :( – Emmanuel Touzery Dec 09 '16 at 23:42
  • immutables 3.8.1 has the bug still => https://github.com/facebook/immutable-js/blob/v3.8.1/type-definitions/Immutable.d.ts#L1965 not sure now how to tell the compiler to use the other definition or something... – Emmanuel Touzery Dec 09 '16 at 23:43
  • OK I think I fixed it with `npm install --save https://github.com/facebook/immutable-js/tarball/0155f1c7b2e9c575b2090ff0e5e9093ae1039c87` (from http://stackoverflow.com/a/32436218/516188) – Emmanuel Touzery Dec 09 '16 at 23:50