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

[Typescript] rollback some of the change on toJS to avoir circular reference #1922

Merged
merged 2 commits into from Dec 23, 2022
Merged
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
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();
}