Skip to content

Commit a63315f

Browse files
committed
fix(wrapProp): correct flag read
1 parent 168efd5 commit a63315f

File tree

3 files changed

+40
-20
lines changed

3 files changed

+40
-20
lines changed

packages/qwik/src/core/qwik.core.api.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,11 +1946,13 @@ export function _walkJSX(ssr: SSRContainer, value: JSXOutput, options: {
19461946
// @public
19471947
export function withLocale<T>(locale: string, fn: () => T): T;
19481948

1949+
// Warning: (ae-forgotten-export) The symbol "WrappedProp" needs to be exported by the entry point index.d.ts
1950+
//
19491951
// @internal
1950-
export const _wrapProp: <T extends Record<any, any>, P extends keyof T>(...args: [T, P?]) => any;
1952+
export const _wrapProp: <T extends object, P extends keyof T>(...args: [T, P?]) => WrappedProp<T, P>;
19511953

19521954
// @internal @deprecated (undocumented)
1953-
export const _wrapSignal: <T extends Record<any, any>, P extends keyof T>(obj: T, prop: P) => any;
1955+
export const _wrapSignal: <T extends object, P extends keyof T>(obj: T, prop: P) => T[P] | WrappedProp<T, P>;
19541956

19551957
// (No @packageDocumentation comment for this package)
19561958

packages/qwik/src/core/reactive-primitives/impl/signal.unit.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { $, isBrowser } from '@qwik.dev/core';
1+
import { $, _wrapProp, isBrowser } from '@qwik.dev/core';
22
import { createDocument, getTestPlatform } from '@qwik.dev/core/testing';
33
import { afterEach, beforeEach, describe, expect, expectTypeOf, it } from 'vitest';
44
import { getDomContainer } from '../../client/dom-container';
@@ -244,6 +244,16 @@ describe('signal', () => {
244244
expect(log).toEqual([1, 2]);
245245
});
246246
});
247+
describe('wrapped', () => {
248+
it('should not re-wrap wrapped signal', () => {
249+
const signal = createSignal(1);
250+
const wrapped = _wrapProp(signal);
251+
expect(wrapped).toHaveProperty('value', 1);
252+
expect(wrapped).not.toBe(signal);
253+
const wrapped2 = _wrapProp(wrapped);
254+
expect(wrapped2).toBe(wrapped);
255+
});
256+
});
247257
});
248258
////////////////////////////////////////
249259

packages/qwik/src/core/reactive-primitives/internal-api.ts

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
import { _CONST_PROPS, _IMMUTABLE } from '../shared/utils/constants';
22
import { assertEqual } from '../shared/error/assert';
33
import { isObject } from '../shared/utils/types';
4-
import { isSignal } from './signal.public';
4+
import { isSignal, type Signal } from './signal.public';
55
import { getStoreTarget } from './impl/store';
66
import { isPropsProxy } from '../shared/jsx/jsx-runtime';
77
import { WrappedSignalFlags } from './types';
88
import { WrappedSignalImpl } from './impl/wrapped-signal-impl';
99
import { AsyncComputedSignalImpl } from './impl/async-computed-signal-impl';
1010

1111
// Keep these properties named like this so they're the same as from wrapSignal
12-
const getValueProp = (p0: any) => p0.value;
13-
const getProp = (p0: any, p1: string) => p0[p1];
12+
const getValueProp = <T>(p0: { value: T }) => p0.value;
13+
const getProp = <T extends object, P extends keyof T>(p0: T, p1: P) => p0[p1];
1414

15-
const getWrapped = (args: any[]) =>
15+
const getWrapped = <T extends object>(args: [T, (keyof T | undefined)?]) =>
1616
new WrappedSignalImpl(null, args.length === 1 ? getValueProp : getProp, args, null);
1717

18+
type PropType<T extends object, P extends keyof T> = P extends keyof T
19+
? T[P]
20+
: 'value' extends keyof T
21+
? T['value']
22+
: never;
23+
type WrappedProp<T extends object, P extends keyof T> = T extends Signal
24+
? WrappedSignalImpl<PropType<T, P>>
25+
: PropType<T, P>;
26+
1827
/**
1928
* This wraps a property access of a possible Signal/Store into a WrappedSignal. The optimizer does
2029
* this automatically when a prop is only used as a prop on JSX.
@@ -26,7 +35,9 @@ const getWrapped = (args: any[]) =>
2635
*
2736
* @internal
2837
*/
29-
export const _wrapProp = <T extends Record<any, any>, P extends keyof T>(...args: [T, P?]): any => {
38+
export const _wrapProp = <T extends object, P extends keyof T>(
39+
...args: [T, P?]
40+
): WrappedProp<T, P> => {
3041
const obj = args[0];
3142
const prop = args.length < 2 ? 'value' : args[1]!;
3243

@@ -37,37 +48,34 @@ export const _wrapProp = <T extends Record<any, any>, P extends keyof T>(...args
3748
if (!(obj instanceof AsyncComputedSignalImpl)) {
3849
assertEqual(prop, 'value', 'Left side is a signal, prop must be value');
3950
}
40-
if (obj instanceof WrappedSignalImpl && obj.flags & WrappedSignalFlags.UNWRAP) {
41-
return obj;
51+
if (obj instanceof WrappedSignalImpl && obj.$flags$ & WrappedSignalFlags.UNWRAP) {
52+
return obj as WrappedProp<T, P>;
4253
}
43-
return getWrapped(args);
54+
return getWrapped(args) as WrappedProp<T, P>;
4455
}
4556
if (isPropsProxy(obj)) {
46-
const constProps = obj[_CONST_PROPS] as any;
57+
const constProps = obj[_CONST_PROPS];
4758
if (constProps && prop in constProps) {
4859
// Const props don't need wrapping
49-
return constProps[prop];
60+
return constProps[prop as keyof typeof constProps] as WrappedProp<T, P>;
5061
}
5162
} else {
5263
const target = getStoreTarget(obj);
5364
if (target) {
54-
const value = target[prop];
65+
const value = target[prop as P];
5566
const wrappedValue = isSignal(value)
5667
? // If the value is already a signal, we don't need to wrap it again
5768
value
5869
: getWrapped(args);
59-
return wrappedValue;
70+
return wrappedValue as WrappedProp<T, P>;
6071
}
6172
}
6273
// the object is not reactive, so we can just return the value
63-
return obj[prop];
74+
return obj[prop as P] as WrappedProp<T, P>;
6475
};
6576

6677
/** @internal @deprecated v1 compat */
67-
export const _wrapSignal = <T extends Record<any, any>, P extends keyof T>(
68-
obj: T,
69-
prop: P
70-
): any => {
78+
export const _wrapSignal = <T extends object, P extends keyof T>(obj: T, prop: P) => {
7179
const r = _wrapProp(obj, prop);
7280
if (r === _IMMUTABLE) {
7381
return obj[prop];

0 commit comments

Comments
 (0)