Skip to content

Commit

Permalink
[Typescript] rollback some of the change on toJS to avoir circular …
Browse files Browse the repository at this point in the history
…reference (#1922)
  • Loading branch information
jdeniau committed Dec 23, 2022
1 parent d88f722 commit ac3a055
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
Dates are formatted as YYYY-MM-DD.

## Unreleased

- [Typescript] rollback some of the change on `toJS` to avoir circular reference

## [4.2.0] - 2022-12-22

- [TypeScript] Better type for toJS [#1917](https://github.com/immutable-js/immutable-js/pull/1917) by [jdeniau](https://github.com/jdeniau)
Expand Down
20 changes: 15 additions & 5 deletions type-definitions/immutable.d.ts
Expand Up @@ -93,24 +93,34 @@
declare namespace Immutable {
/**
* @ignore
*
* Used to convert deeply all immutable types to a plain TS type.
* Using `unknown` on object instead of recursive call as we have a circular reference issue
*/
export type DeepCopy<T> = T extends Collection.Keyed<infer KeyedKey, infer V>
export type DeepCopy<T> = T extends Record<infer R>
? // convert Record to DeepCopy plain JS object
{
[key in keyof R]: R[key] extends object ? unknown : R[key];
}
: T extends Collection.Keyed<infer KeyedKey, infer V>
? // convert KeyedCollection to DeepCopy plain JS object
{
[key in KeyedKey extends string | number | symbol
? KeyedKey
: string]: DeepCopy<V>;
: string]: V extends object ? unknown : V;
}
: // convert IndexedCollection or Immutable.Set to DeepCopy plain JS array
T extends Collection<infer _, infer V>
? Array<DeepCopy<V>>
? Array<V extends object ? unknown : V>
: T extends string | number // Iterable scalar types : should be kept as is
? T
: T extends Iterable<infer V> // Iterable are converted to plain JS array
? Array<DeepCopy<V>>
? Array<V extends object ? unknown : V>
: T extends object // plain JS object are converted deeply
? {
[ObjectKey in keyof T]: DeepCopy<T[ObjectKey]>;
[ObjectKey in keyof T]: T[ObjectKey] extends object
? unknown
: T[ObjectKey];
}
: // other case : should be kept as is
T;
Expand Down
31 changes: 20 additions & 11 deletions type-definitions/ts-tests/deepCopy.ts
Expand Up @@ -5,23 +5,16 @@ import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable';

// $ExpectType { a: number; b: number; }
type Test = DeepCopy<{ a: number; b: number }>;
// ^?

// $ExpectType number
type TestA = Test['a'];
// ^?
}

{
// Iterables

// $ExpectType string[]
type Test = DeepCopy<string[]>;
// ^?

// $ExpectType number[]
type Keyed = DeepCopy<Collection.Indexed<number>>;
// ^?
}

{
Expand All @@ -30,10 +23,12 @@ import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable';
// $ExpectType { [x: string]: string; }
type StringKey = DeepCopy<Map<string, string>>;

// $ExpectType { [x: string]: object; }
// should be `{ [x: string]: object; }` but there is an issue with circular references
// $ExpectType { [x: string]: unknown; }
type ObjectKey = DeepCopy<Map<object, object>>;

// $ExpectType { [x: string]: object; [x: number]: object; }
// should be `{ [x: string]: object; [x: number]: object; }` but there is an issue with circular references
// $ExpectType { [x: string]: unknown; [x: number]: unknown; }
type MixedKey = DeepCopy<Map<object | number, object>>;

// $ExpectType string[]
Expand Down Expand Up @@ -62,9 +57,23 @@ import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable';
{
// Nested

// $ExpectType { map: { [x: string]: string; }; list: string[]; set: string[]; }
// should be `{ map: { [x: string]: string; }; list: string[]; set: string[]; }` but there is an issue with circular references
// $ExpectType { map: unknown; list: unknown; set: unknown; }
type NestedObject = DeepCopy<{ map: Map<string, string>; list: List<string>; set: Set<string>; }>;

// $ExpectType { map: { [x: string]: string; }; }
// should be `{ map: { [x: string]: string; }; }`, but there is an issue with circular references
// $ExpectType { map: unknown; }
type NestedMap = DeepCopy<Map<'map', Map<string, string>>>;
}

{
// Circular references

type Article = Record<{ title: string; tag: Tag; }>;
type Tag = Record<{ name: string; article: Article; }>;

// should handle circular references here somehow
// $ExpectType { title: string; tag: unknown; }
type Circular = DeepCopy<Article>;
// ^?
}
3 changes: 2 additions & 1 deletion type-definitions/ts-tests/record.ts
Expand Up @@ -88,6 +88,7 @@ import { List, Map, Record, Set } from 'immutable';
// $ExpectType { map: Map<string, string>; list: List<string>; set: Set<string>; }
withMap.toJSON();

// $ExpectType { map: { [x: string]: string; }; list: string[]; set: string[]; }
// should be `{ map: { [x: string]: string; }; list: string[]; set: string[]; }` but there is an issue with circular references
// $ExpectType { map: unknown; list: unknown; set: unknown; }
withMap.toJS();
}

0 comments on commit ac3a055

Please sign in to comment.