Skip to content

Commit

Permalink
fix: extend check to other built-in object types
Browse files Browse the repository at this point in the history
  • Loading branch information
markostanimirovic committed Dec 9, 2024
1 parent d4abbd8 commit 5d66296
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 128 deletions.
72 changes: 60 additions & 12 deletions modules/signals/spec/deep-signal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { toDeepSignal } from '../src/deep-signal';
import { isSignal, signal } from '@angular/core';
import { toDeepSignal } from '../src/deep-signal';

describe('toDeepSignal', () => {
it('creates deep signals for plain objects', () => {
Expand Down Expand Up @@ -56,27 +56,53 @@ describe('toDeepSignal', () => {
expect(deepBool).toBe(bool);
});

it('does not create deep signals for built-in object types', () => {
it('does not create deep signals for iterables', () => {
const array = signal([]);
const set = signal(new Set());
const map = signal(new Map());
const date = signal(new Date());
const error = signal(new Error());
const regExp = signal(new RegExp(''));
const uintArray = signal(new Uint32Array());
const floatArray = signal(new Float64Array());

const deepArray = toDeepSignal(array);
const deepSet = toDeepSignal(set);
const deepMap = toDeepSignal(map);
const deepDate = toDeepSignal(date);
const deepError = toDeepSignal(error);
const deepRegExp = toDeepSignal(regExp);
const deepUintArray = toDeepSignal(uintArray);
const deepFloatArray = toDeepSignal(floatArray);

expect(deepArray).toBe(array);
expect(deepSet).toBe(set);
expect(deepMap).toBe(map);
expect(deepUintArray).toBe(uintArray);
expect(deepFloatArray).toBe(floatArray);
});

it('does not create deep signals for built-in object types', () => {
const weakSet = signal(new WeakSet());
const weakMap = signal(new WeakMap());
const promise = signal(Promise.resolve(10));
const date = signal(new Date());
const error = signal(new Error());
const regExp = signal(new RegExp(''));
const arrayBuffer = signal(new ArrayBuffer(10));
const dataView = signal(new DataView(new ArrayBuffer(10)));

const deepWeakSet = toDeepSignal(weakSet);
const deepWeakMap = toDeepSignal(weakMap);
const deepPromise = toDeepSignal(promise);
const deepDate = toDeepSignal(date);
const deepError = toDeepSignal(error);
const deepRegExp = toDeepSignal(regExp);
const deepArrayBuffer = toDeepSignal(arrayBuffer);
const deepDataView = toDeepSignal(dataView);

expect(deepWeakSet).toBe(weakSet);
expect(deepWeakMap).toBe(weakMap);
expect(deepPromise).toBe(promise);
expect(deepDate).toBe(date);
expect(deepError).toBe(error);
expect(deepRegExp).toBe(regExp);
expect(deepArrayBuffer).toBe(arrayBuffer);
expect(deepDataView).toBe(dataView);
});

it('does not create deep signals for functions', () => {
Expand All @@ -93,21 +119,43 @@ describe('toDeepSignal', () => {
expect(deepFn3).toBe(fn3);
});

it('does not create deep signals for custom class instances that extend built-in object types', () => {
it('does not create deep signals for custom class instances that are iterables', () => {
class CustomArray extends Array {}

class CustomSet extends Set {}
class CustomError extends Error {}

class CustomFloatArray extends Float32Array {}

const array = signal(new CustomArray());
const floatArray = signal(new CustomFloatArray());
const set = signal(new CustomSet());
const error = signal(new CustomError());

const deepArray = toDeepSignal(array);
const deepFloatArray = toDeepSignal(floatArray);
const deepSet = toDeepSignal(set);
const deepError = toDeepSignal(error);

expect(deepArray).toBe(array);
expect(deepFloatArray).toBe(floatArray);
expect(deepSet).toBe(set);
});

it('does not create deep signals for custom class instances that extend built-in object types', () => {
class CustomWeakMap extends WeakMap {}

class CustomError extends Error {}

class CustomArrayBuffer extends ArrayBuffer {}

const weakMap = signal(new CustomWeakMap());
const error = signal(new CustomError());
const arrayBuffer = signal(new CustomArrayBuffer(10));

const deepWeakMap = toDeepSignal(weakMap);
const deepError = toDeepSignal(error);
const deepArrayBuffer = toDeepSignal(arrayBuffer);

expect(deepWeakMap).toBe(weakMap);
expect(deepError).toBe(error);
expect(deepArrayBuffer).toBe(arrayBuffer);
});
});
90 changes: 41 additions & 49 deletions modules/signals/spec/types/signal-state.types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,91 +118,83 @@ describe('signalState', () => {
expectSnippet(snippet).toInfer('set', 'Signal<Set<{ foo: number; }>>');
});

it('does not create deep signals for an array', () => {
it('does not create deep signals for iterables', () => {
const snippet = `
const state = signalState<string[]>([]);
declare const stateKeys: keyof typeof state;
const arrayState = signalState<string[]>([]);
declare const arrayStateKeys: keyof typeof arrayState;
const setState = signalState(new Set<number>());
declare const setStateKeys: keyof typeof setState;
const mapState = signalState(new Map<number, { bar: boolean }>());
declare const mapStateKeys: keyof typeof mapState;
const uintArrayState = signalState(new Uint8ClampedArray());
declare const uintArrayStateKeys: keyof typeof uintArrayState;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer(
'stateKeys',
'arrayStateKeys',
'unique symbol | keyof Signal<string[]>'
);
});

it('does not create deep signals for Set', () => {
const snippet = `
const state = signalState(new Set<number>());
declare const stateKeys: keyof typeof state;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer(
'stateKeys',
'setStateKeys',
'unique symbol | keyof Signal<Set<number>>'
);
});

it('does not create deep signals for Map', () => {
const snippet = `
const state = signalState(new Map<number, { bar: boolean }>());
declare const stateKeys: keyof typeof state;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer(
'stateKeys',
'mapStateKeys',
'unique symbol | keyof Signal<Map<number, { bar: boolean; }>>'
);
});

it('does not create deep signals for Date', () => {
const snippet = `
const state = signalState(new Date());
declare const stateKeys: keyof typeof state;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer(
'stateKeys',
'unique symbol | keyof Signal<Date>'
'uintArrayStateKeys',
'unique symbol | keyof Signal<Uint8ClampedArray>'
);
});

it('does not create deep signals for Error', () => {
it('does not create deep signals for built-in object types', () => {
const snippet = `
const state = signalState(new Error());
declare const stateKeys: keyof typeof state;
const weakSetState = signalState(new WeakSet<{ foo: string }>());
declare const weakSetStateKeys: keyof typeof weakSetState;
const dateState = signalState(new Date());
declare const dateStateKeys: keyof typeof dateState;
const errorState = signalState(new Error());
declare const errorStateKeys: keyof typeof errorState;
const regExpState = signalState(new RegExp(''));
declare const regExpStateKeys: keyof typeof regExpState;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer(
'stateKeys',
'unique symbol | keyof Signal<Error>'
'weakSetStateKeys',
'unique symbol | keyof Signal<WeakSet<{ foo: string; }>>'
);
});

it('does not create deep signals for RegExp', () => {
const snippet = `
const state = signalState(new RegExp(''));
declare const stateKeys: keyof typeof state;
`;
expectSnippet(snippet).toInfer(
'dateStateKeys',
'unique symbol | keyof Signal<Date>'
);

expectSnippet(snippet).toSucceed();
expectSnippet(snippet).toInfer(
'errorStateKeys',
'unique symbol | keyof Signal<Error>'
);

expectSnippet(snippet).toInfer(
'stateKeys',
'regExpStateKeys',
'unique symbol | keyof Signal<RegExp>'
);
});

it('does not create deep signals for Function', () => {
it('does not create deep signals for functions', () => {
const snippet = `
const state = signalState(() => {});
declare const stateKeys: keyof typeof state;
Expand Down
88 changes: 35 additions & 53 deletions modules/signals/spec/types/signal-store.types.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,79 +163,61 @@ describe('signalStore', () => {
expectSnippet(snippet).toInfer('set', 'Signal<Set<number>>');
});

it('does not create deep signals when state type is an array', () => {
it('does not create deep signals when state type is an iterable', () => {
const snippet = `
const Store = signalStore(withState<number[]>([]));
const store = new Store();
declare const storeKeys: keyof typeof store;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer('storeKeys', 'unique symbol');
});

it('does not create deep signals when state type is Set', () => {
const snippet = `
const Store = signalStore(withState(new Set<{ foo: string }>()));
const store = new Store();
declare const storeKeys: keyof typeof store;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer('storeKeys', 'unique symbol');
});

it('does not create deep signals when state type is Map', () => {
const snippet = `
const Store = signalStore(withState(new Map<string, { foo: number }>()));
const store = new Store();
declare const storeKeys: keyof typeof store;
`;
const ArrayStore = signalStore(withState<number[]>([]));
const arrayStore = new ArrayStore();
declare const arrayStoreKeys: keyof typeof arrayStore;
expectSnippet(snippet).toSucceed();
const SetStore = signalStore(withState(new Set<{ foo: string }>()));
const setStore = new SetStore();
declare const setStoreKeys: keyof typeof setStore;
expectSnippet(snippet).toInfer('storeKeys', 'unique symbol');
});
const MapStore = signalStore(withState(new Map<string, { foo: number }>()));
const mapStore = new MapStore();
declare const mapStoreKeys: keyof typeof mapStore;
it('does not create deep signals when state type is Date', () => {
const snippet = `
const Store = signalStore(withState(new Date()));
const store = new Store();
declare const storeKeys: keyof typeof store;
const FloatArrayStore = signalStore(withState(new Float32Array()));
const floatArrayStore = new FloatArrayStore();
declare const floatArrayStoreKeys: keyof typeof floatArrayStore;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer('storeKeys', 'unique symbol');
expectSnippet(snippet).toInfer('arrayStoreKeys', 'unique symbol');
expectSnippet(snippet).toInfer('setStoreKeys', 'unique symbol');
expectSnippet(snippet).toInfer('mapStoreKeys', 'unique symbol');
expectSnippet(snippet).toInfer('floatArrayStoreKeys', 'unique symbol');
});

it('does not create deep signals when state type is Error', () => {
it('does not create deep signals when state type is a built-in object type', () => {
const snippet = `
const Store = signalStore(withState(new Error()));
const store = new Store();
declare const storeKeys: keyof typeof store;
`;
const WeakMapStore = signalStore(withState(new WeakMap<{ foo: string }, { bar: number }>()));
const weakMapStore = new WeakMapStore();
declare const weakMapStoreKeys: keyof typeof weakMapStore;
expectSnippet(snippet).toSucceed();
const DateStore = signalStore(withState(new Date()));
const dateStore = new DateStore();
declare const dateStoreKeys: keyof typeof dateStore;
expectSnippet(snippet).toInfer('storeKeys', 'unique symbol');
});
const ErrorStore = signalStore(withState(new Error()));
const errorStore = new ErrorStore();
declare const errorStoreKeys: keyof typeof errorStore;
it('does not create deep signals when state type is RegExp', () => {
const snippet = `
const Store = signalStore(withState(new RegExp('')));
const store = new Store();
declare const storeKeys: keyof typeof store;
const RegExpStore = signalStore(withState(new RegExp('')));
const regExpStore = new RegExpStore();
declare const regExpStoreKeys: keyof typeof regExpStore;
`;

expectSnippet(snippet).toSucceed();

expectSnippet(snippet).toInfer('storeKeys', 'unique symbol');
expectSnippet(snippet).toInfer('weakMapStoreKeys', 'unique symbol');
expectSnippet(snippet).toInfer('dateStoreKeys', 'unique symbol');
expectSnippet(snippet).toInfer('errorStoreKeys', 'unique symbol');
expectSnippet(snippet).toInfer('regExpStoreKeys', 'unique symbol');
});

it('does not create deep signals when state type is Function', () => {
it('does not create deep signals when state type is a function', () => {
const snippet = `
const Store = signalStore(withState(() => () => {}));
const store = new Store();
Expand Down
Loading

0 comments on commit 5d66296

Please sign in to comment.