Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix TypeScript typedefs to allow arrays of tuples #1727

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 35 additions & 23 deletions type-definitions/Immutable.d.ts
Expand Up @@ -182,7 +182,7 @@ declare module Immutable {
*/
export function List(): List<unknown>;
export function List<T>(): List<T>;
export function List<T>(collection: Iterable<T>): List<T>;
export function List<T>(collection: Array<T> | Iterable<T>): List<T>;

export interface List<T> extends Collection.Indexed<T> {

Expand Down Expand Up @@ -546,7 +546,7 @@ declare module Immutable {
* @alias merge
*/
concat<C>(...valuesOrCollections: Array<Iterable<C> | C>): List<T | C>;
merge<C>(...collections: Array<Iterable<C>>): List<T | C>;
merge<C>(...valuesOrCollections: Array<Iterable<C> | C>): List<T | C>;

/**
* Returns a new List with values passed through a
Expand Down Expand Up @@ -758,7 +758,7 @@ declare module Immutable {
* but since Immutable Map keys can be of any type the argument to `get()` is
* not altered.
*/
export function Map<K, V>(collection: Iterable<[K, V]>): Map<K, V>;
export function Map<K, V>(collection: Array<[K, V]> | Iterable<[K, V]>): Map<K, V>;
export function Map<V>(obj: {[key: string]: V}): Map<string, V>;
export function Map<K, V>(): Map<K, V>;
export function Map(): Map<unknown, unknown>;
Expand Down Expand Up @@ -979,9 +979,13 @@ declare module Immutable {
*
* @alias concat
*/
merge<KC, VC>(...collections: Array<Array<[KC, VC]>>): Map<K | KC, V | VC>;
merge<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
merge<KC, VC>(...collections: Array<Array<[KC, VC]> | Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
merge<C>(...collections: Array<{[key: string]: C}>): Map<K | string, V | C>;
concat<KC, VC>(...collections: Array<Array<[KC, VC]>>): Map<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Array<[KC, VC]> | Iterable<[KC, VC]>>): Map<K | KC, V | VC>;
concat<C>(...collections: Array<{[key: string]: C}>): Map<K | string, V | C>;

/**
Expand All @@ -1004,7 +1008,7 @@ declare module Immutable {
*/
mergeWith(
merger: (oldVal: V, newVal: V, key: K) => V,
...collections: Array<Iterable<[K, V]> | {[key: string]: V}>
...collections: Array<Array<[K, V]> | Iterable<[K, V]> | {[key: string]: V}>
): this;

/**
Expand All @@ -1030,7 +1034,7 @@ declare module Immutable {
*
* Note: `mergeDeep` can be used in `withMutations`.
*/
mergeDeep(...collections: Array<Iterable<[K, V]> | {[key: string]: V}>): this;
mergeDeep(...collections: Array<Array<[K, V]> | Iterable<[K, V]> | {[key: string]: V}>): this;

/**
* Like `mergeDeep()`, but when two non-Collections conflict, it uses the
Expand All @@ -1053,7 +1057,7 @@ declare module Immutable {
*/
mergeDeepWith(
merger: (oldVal: unknown, newVal: unknown, key: unknown) => unknown,
...collections: Array<Iterable<[K, V]> | {[key: string]: V}>
...collections: Array<Array<[K, V]> | Iterable<[K, V]> | {[key: string]: V}>
): this;


Expand Down Expand Up @@ -1355,7 +1359,7 @@ declare module Immutable {
* Similar to `data.map(...).flatten(true)`.
*/
flatMap<KM, VM>(
mapper: (value: V, key: K, iter: this) => Iterable<[KM, VM]>,
mapper: (value: V, key: K, iter: this) => Array<[KM, VM]> | Iterable<[KM, VM]>,
context?: unknown
): Map<KM, VM>;

Expand Down Expand Up @@ -1417,7 +1421,7 @@ declare module Immutable {
* Note: `OrderedMap` is a factory function and not a class, and does not use
* the `new` keyword during construction.
*/
export function OrderedMap<K, V>(collection: Iterable<[K, V]>): OrderedMap<K, V>;
export function OrderedMap<K, V>(collection: Array<[K, V]> | Iterable<[K, V]>): OrderedMap<K, V>;
export function OrderedMap<V>(obj: {[key: string]: V}): OrderedMap<string, V>;
export function OrderedMap<K, V>(): OrderedMap<K, V>;
export function OrderedMap(): OrderedMap<unknown, unknown>;
Expand Down Expand Up @@ -1471,9 +1475,13 @@ declare module Immutable {
*
* @alias concat
*/
merge<KC, VC>(...collections: Array<Array<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
merge<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
merge<KC, VC>(...collections: Array<Array<[KC, VC]> | Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
merge<C>(...collections: Array<{[key: string]: C}>): OrderedMap<K | string, V | C>;
concat<KC, VC>(...collections: Array<Array<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Array<[KC, VC]> | Iterable<[KC, VC]>>): OrderedMap<K | KC, V | VC>;
concat<C>(...collections: Array<{[key: string]: C}>): OrderedMap<K | string, V | C>;

// Sequence algorithms
Expand Down Expand Up @@ -1515,7 +1523,7 @@ declare module Immutable {
* Similar to `data.map(...).flatten(true)`.
*/
flatMap<KM, VM>(
mapper: (value: V, key: K, iter: this) => Iterable<[KM, VM]>,
mapper: (value: V, key: K, iter: this) => Array<[KM, VM]> | Iterable<[KM, VM]>,
context?: unknown
): OrderedMap<KM, VM>;

Expand Down Expand Up @@ -1612,7 +1620,7 @@ declare module Immutable {
*/
export function Set(): Set<unknown>;
export function Set<T>(): Set<T>;
export function Set<T>(collection: Iterable<T>): Set<T>;
export function Set<T>(collection: Array<T> | Iterable<T>): Set<T>;

export interface Set<T> extends Collection.Set<T> {

Expand Down Expand Up @@ -1796,7 +1804,7 @@ declare module Immutable {
*/
export function OrderedSet(): OrderedSet<unknown>;
export function OrderedSet<T>(): OrderedSet<T>;
export function OrderedSet<T>(collection: Iterable<T>): OrderedSet<T>;
export function OrderedSet<T>(collection: Array<T> | Iterable<T>): OrderedSet<T>;

export interface OrderedSet<T> extends Set<T> {

Expand Down Expand Up @@ -1956,7 +1964,7 @@ declare module Immutable {
*/
export function Stack(): Stack<unknown>;
export function Stack<T>(): Stack<T>;
export function Stack<T>(collection: Iterable<T>): Stack<T>;
export function Stack<T>(collection: Array<T> | Iterable<T>): Stack<T>;

export interface Stack<T> extends Collection.Indexed<T> {

Expand Down Expand Up @@ -2693,7 +2701,7 @@ declare module Immutable {
* Note: `Seq.Keyed` is a conversion function and not a class, and does not
* use the `new` keyword during construction.
*/
export function Keyed<K, V>(collection: Iterable<[K, V]>): Seq.Keyed<K, V>;
export function Keyed<K, V>(collection: Array<[K, V]> | Iterable<[K, V]>): Seq.Keyed<K, V>;
export function Keyed<V>(obj: {[key: string]: V}): Seq.Keyed<string, V>;
export function Keyed<K, V>(): Seq.Keyed<K, V>;
export function Keyed(): Seq.Keyed<unknown, unknown>;
Expand Down Expand Up @@ -2729,7 +2737,9 @@ declare module Immutable {
* All entries will be present in the resulting Seq, even if they
* have the same key.
*/
concat<KC, VC>(...collections: Array<Array<[KC, VC]>>): Seq.Keyed<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Seq.Keyed<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Array<[KC, VC]> | Iterable<[KC, VC]>>): Seq.Keyed<K | KC, V | VC>;
concat<C>(...collections: Array<{[key: string]: C}>): Seq.Keyed<K | string, V | C>;

/**
Expand Down Expand Up @@ -2772,7 +2782,7 @@ declare module Immutable {
* Similar to `seq.map(...).flatten(true)`.
*/
flatMap<KM, VM>(
mapper: (value: V, key: K, iter: this) => Iterable<[KM, VM]>,
mapper: (value: V, key: K, iter: this) => Array<[KM, VM]> | Iterable<[KM, VM]>,
context?: unknown
): Seq.Keyed<KM, VM>;

Expand Down Expand Up @@ -2819,7 +2829,7 @@ declare module Immutable {
*/
export function Indexed(): Seq.Indexed<unknown>;
export function Indexed<T>(): Seq.Indexed<T>;
export function Indexed<T>(collection: Iterable<T>): Seq.Indexed<T>;
export function Indexed<T>(collection: Array<T> | Iterable<T>): Seq.Indexed<T>;

export interface Indexed<T> extends Seq<number, T>, Collection.Indexed<T> {
/**
Expand Down Expand Up @@ -2971,7 +2981,7 @@ declare module Immutable {
*/
export function Set(): Seq.Set<unknown>;
export function Set<T>(): Seq.Set<T>;
export function Set<T>(collection: Iterable<T>): Seq.Set<T>;
export function Set<T>(collection: Array<T> | Iterable<T>): Seq.Set<T>;

export interface Set<T> extends Seq<T, T>, Collection.Set<T> {
/**
Expand Down Expand Up @@ -3071,7 +3081,7 @@ declare module Immutable {
export function Seq<K, V>(collection: Collection.Keyed<K, V>): Seq.Keyed<K, V>;
export function Seq<T>(collection: Collection.Indexed<T>): Seq.Indexed<T>;
export function Seq<T>(collection: Collection.Set<T>): Seq.Set<T>;
export function Seq<T>(collection: Iterable<T>): Seq.Indexed<T>;
export function Seq<T>(collection: Array<T> | Iterable<T>): Seq.Indexed<T>;
export function Seq<V>(obj: {[key: string]: V}): Seq.Keyed<string, V>;
export function Seq(): Seq<unknown, unknown>;

Expand Down Expand Up @@ -3246,7 +3256,7 @@ declare module Immutable {
* Note: `Collection.Keyed` is a conversion function and not a class, and
* does not use the `new` keyword during construction.
*/
export function Keyed<K, V>(collection: Iterable<[K, V]>): Collection.Keyed<K, V>;
export function Keyed<K, V>(collection: Array<[K, V]> | Iterable<[K, V]>): Collection.Keyed<K, V>;
export function Keyed<V>(obj: {[key: string]: V}): Collection.Keyed<string, V>;

export interface Keyed<K, V> extends Collection<K, V> {
Expand Down Expand Up @@ -3294,7 +3304,9 @@ declare module Immutable {
/**
* Returns a new Collection with other collections concatenated to this one.
*/
concat<KC, VC>(...collections: Array<Array<[KC, VC]>>): Collection.Keyed<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Iterable<[KC, VC]>>): Collection.Keyed<K | KC, V | VC>;
concat<KC, VC>(...collections: Array<Array<[KC, VC]> | Iterable<[KC, VC]>>): Collection.Keyed<K | KC, V | VC>;
concat<C>(...collections: Array<{[key: string]: C}>): Collection.Keyed<K | string, V | C>;

/**
Expand Down Expand Up @@ -3360,7 +3372,7 @@ declare module Immutable {
* Similar to `collection.map(...).flatten(true)`.
*/
flatMap<KM, VM>(
mapper: (value: V, key: K, iter: this) => Iterable<[KM, VM]>,
mapper: (value: V, key: K, iter: this) => Array<[KM, VM]> | Iterable<[KM, VM]>,
context?: unknown
): Collection.Keyed<KM, VM>;

Expand Down Expand Up @@ -3407,7 +3419,7 @@ declare module Immutable {
* Note: `Collection.Indexed` is a conversion function and not a class, and
* does not use the `new` keyword during construction.
*/
export function Indexed<T>(collection: Iterable<T>): Collection.Indexed<T>;
export function Indexed<T>(collection: Array<T> | Iterable<T>): Collection.Indexed<T>;

export interface Indexed<T> extends Collection<number, T> {
/**
Expand Down Expand Up @@ -3700,7 +3712,7 @@ declare module Immutable {
* Note: `Collection.Set` is a factory function and not a class, and does
* not use the `new` keyword during construction.
*/
export function Set<T>(collection: Iterable<T>): Collection.Set<T>;
export function Set<T>(collection: Array<T> | Iterable<T>): Collection.Set<T>;

export interface Set<T> extends Collection<T, T> {
/**
Expand Down Expand Up @@ -3802,7 +3814,7 @@ declare module Immutable {
* use the `new` keyword during construction.
*/
export function Collection<I extends Collection<unknown, unknown>>(collection: I): I;
export function Collection<T>(collection: Iterable<T>): Collection.Indexed<T>;
export function Collection<T>(collection: Array<T> | Iterable<T>): Collection.Indexed<T>;
export function Collection<V>(obj: {[key: string]: V}): Collection.Keyed<string, V>;

export interface Collection<K, V> extends ValueObject {
Expand Down Expand Up @@ -4476,7 +4488,7 @@ declare module Immutable {
* Used for Dictionaries only.
*/
flatMap<KM, VM>(
mapper: (value: V, key: K, iter: this) => Iterable<[KM, VM]>,
mapper: (value: V, key: K, iter: this) => Array<[KM, VM]> | Iterable<[KM, VM]>,
context?: unknown
): Collection<KM, VM>;

Expand Down
17 changes: 17 additions & 0 deletions type-definitions/ts-tests/collections.ts
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import { Collection } from '../../';

{ // #constructor

// $ExpectType Indexed<number>
Collection([ 1, 2, 3 ]);

// $ExpectType Indexed<[number, string]>
Collection<[number, string]>([[1, 'number']]);
}
12 changes: 6 additions & 6 deletions type-definitions/ts-tests/exports.ts
Expand Up @@ -32,9 +32,9 @@ Seq; // $ExpectType typeof Seq
Set; // $ExpectType typeof Set
Stack; // $ExpectType typeof Stack
Collection; // $ExpectType typeof Collection
Collection.Set; // $ExpectType <T>(collection: Iterable<T>) => Set<T>
Collection.Keyed; // $ ExpectType { <K, V>(collection: Iterable<[K, V]>): Keyed<K, V>; <V>(obj: { [key: string]: V; }): Keyed<string, V> }
Collection.Indexed; // $ExpectType <T>(collection: Iterable<T>) => Indexed<T>
Collection.Set; // $ExpectType <T>(collection: T[] | Iterable<T>) => Set<T>
Collection.Keyed; // $ ExpectType { <K, V>(collection: Array<[K, V]> | Iterable<[K, V]>): Keyed<K, V>; <V>(obj: { [key: string]: V; }): Keyed<string, V> }
Collection.Indexed; // $ExpectType <T>(collection: T[] | Iterable<T>) => Indexed<T>

Immutable.List; // $ExpectType typeof List
Immutable.Map; // $ExpectType typeof Map
Expand All @@ -47,6 +47,6 @@ Immutable.Seq; // $ExpectType typeof Seq
Immutable.Set; // $ExpectType typeof Set
Immutable.Stack; // $ExpectType typeof Stack
Immutable.Collection; // $ExpectType typeof Collection
Immutable.Collection.Set; // $ExpectType <T>(collection: Iterable<T>) => Set<T>
Immutable.Collection.Keyed; // $ ExpectType { <K, V>(collection: Iterable<[K, V]>): Keyed<K, V>; <V>(obj: { [key: string]: V; }): Keyed<string, V> }
Immutable.Collection.Indexed; // $ExpectType <T>(collection: Iterable<T>) => Indexed<T>
Immutable.Collection.Set; // $ExpectType <T>(collection: T[] | Iterable<T>) => Set<T>
Immutable.Collection.Keyed; // $ ExpectType { <K, V>(collection: Array<[K, V]> | Iterable<[K, V]>): Keyed<K, V>; <V>(obj: { [key: string]: V; }): Keyed<string, V> }
Immutable.Collection.Indexed; // $ExpectType <T>(collection: T[] | Iterable<T>) => Indexed<T>
67 changes: 62 additions & 5 deletions type-definitions/ts-tests/list.ts
Expand Up @@ -26,6 +26,9 @@ import {
const numberList: List<number> = List();
const numberOrStringList: List<number | string> = List([1, 'a']);

// $ExpectType List<[number, string]>
List<[number, string]>([[1, 'a']]);

// $ExpectError
const invalidNumberList: List<number> = List([1, 'a']);
}
Expand Down Expand Up @@ -332,20 +335,77 @@ import {

{ // #merge

//
// same type:

// $ExpectType List<number>
List<number>().merge(List<number>());

// $ExpectType List<number>
List<number>().merge([1]);

// $ExpectType List<number>
List<number>().merge(1);

// $ExpectType List<number>
List<number>().merge(1, [1]);

// $ExpectType List<number>
List<number>().merge(1, List<number>());

// $ExpectType List<number>
List<number>().merge(1, [1], List<number>());

//
// auto-merging different types:

// $ExpectType List<string | number>
List<number>().merge(List<string>());

// $ExpectType List<string | number>
List<number>().merge(['a']);

// $ExpectType List<string | number>
List<number>().merge('a');

// $ExpectType List<string | number>
List<number>().merge('a', ['a']);

// $ExpectType List<string | number>
List<number>().merge('a', List<string>());

// $ExpectType List<string | number>
List<number>().merge('a', ['a'], List<string>());

//
// manually merging different types:

// $ExpectType List<string | number>
List<number>().merge<string | number>(1, ['a']);

// $ExpectType List<string | number>
List<number>().merge<string | number>('a', List<number>());

// $ExpectType List<string | number>
List<number>().merge<string | number>(1, ['a'], List<number>());

//
// merging subtype into supertype:

// $ExpectType List<string | number>
List<number | string>().merge(List<string>());

// $ExpectType List<string | number>
List<number | string>().merge(List<number>());

//
// merge() standalone function (rather than .merge() method)

// $ExpectType List<number>
merge(List<number>(), List<number>());

// $ExpectType List<number>
merge(List<number>(), [1]);
}

{ // #mergeIn
Expand Down Expand Up @@ -396,9 +456,6 @@ import {
List<number>().asImmutable();
}

{ // # for of loops
const list = List([ 1, 2, 3, 4 ]);
for (const val of list) {
const v: number = val;
}
{ // # iterable, for compatibility with for-of loops
const iterable: Iterable<number> = List([ 1, 2, 3, 4 ]);
}