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

manage to handle toJS circular reference. #1932

Merged
merged 1 commit into from Aug 23, 2023
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
12 changes: 5 additions & 7 deletions type-definitions/immutable.d.ts
Expand Up @@ -100,27 +100,25 @@ declare namespace Immutable {
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];
[key in keyof R]: DeepCopy<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]: V extends object ? unknown : V;
: string]: DeepCopy<V>;
}
: // convert IndexedCollection or Immutable.Set to DeepCopy plain JS array
T extends Collection<infer _, infer V>
? Array<V extends object ? unknown : V>
? Array<DeepCopy<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<V extends object ? unknown : V>
? Array<DeepCopy<V>>
: T extends object // plain JS object are converted deeply
? {
[ObjectKey in keyof T]: T[ObjectKey] extends object
? unknown
: T[ObjectKey];
[ObjectKey in keyof T]: DeepCopy<T[ObjectKey]>;
}
: // other case : should be kept as is
T;
Expand Down
16 changes: 5 additions & 11 deletions type-definitions/ts-tests/deepCopy.ts
Expand Up @@ -23,12 +23,10 @@ import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable';
// $ExpectType { [x: string]: string; }
type StringKey = DeepCopy<Map<string, string>>;

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

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

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

// 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; }
// $ExpectType { map: { [x: string]: string; }; list: string[]; set: string[]; }
type NestedObject = DeepCopy<{ map: Map<string, string>; list: List<string>; set: Set<string>; }>;

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

Expand All @@ -72,8 +68,6 @@ import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable';
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; }
// $ExpectType { title: string; tag: { name: string; article: any; }; }
type Circular = DeepCopy<Article>;
// ^?
}
30 changes: 27 additions & 3 deletions type-definitions/ts-tests/record.ts
@@ -1,4 +1,4 @@
import { List, Map, Record, Set } from 'immutable';
import { List, Map, Record, RecordOf, Set } from 'immutable';

{
// Factory
Expand Down Expand Up @@ -88,7 +88,31 @@ import { List, Map, Record, Set } from 'immutable';
// $ExpectType { map: Map<string, string>; list: List<string>; set: Set<string>; }
withMap.toJSON();

// 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; }
// $ExpectType { map: { [x: string]: string; }; list: string[]; set: string[]; }
withMap.toJS();
}

{
// optional properties

interface Size { distance: string; }

const Line = Record<{ size?: Size, color?: string }>({ size: undefined, color: 'red' });

const line = Line({});

// $ExpectType { size?: { distance: string; } | undefined; color?: string | undefined; }
line.toJS();
}

{
// similar properties, but one is optional. See https://github.com/immutable-js/immutable-js/issues/1930

interface Id { value: string; }

type A = RecordOf<{ id: Id }>;
type B = RecordOf<{ id?: Id }>;

const a: A = null as any;
const b: B = a;
}