diff --git a/packages/solid/src/render/component.ts b/packages/solid/src/render/component.ts index 5775162f8..b3cb707c5 100644 --- a/packages/solid/src/render/component.ts +++ b/packages/solid/src/render/component.ts @@ -293,17 +293,20 @@ export function splitProps< if (SUPPORTS_PROXY && $PROXY in props) { const blocked = len > 1 ? keys.flat() : keys[0]; + const claimed = new Set(); const res = keys.map(k => { + // a key belongs to the first group that lists it (matches non-proxy path) + const owned = k.filter(property => !claimed.has(property) && (claimed.add(property), true)); return new Proxy( { get(property) { - return k.includes(property) ? props[property as any] : undefined; + return owned.includes(property) ? props[property as any] : undefined; }, has(property) { - return k.includes(property) && property in props; + return owned.includes(property) && property in props; }, keys() { - return k.filter(property => property in props); + return owned.filter(property => property in props); } }, propTraps diff --git a/packages/solid/test/component.spec.ts b/packages/solid/test/component.spec.ts index 1d4424932..eb4b65767 100644 --- a/packages/solid/test/component.spec.ts +++ b/packages/solid/test/component.spec.ts @@ -417,6 +417,31 @@ describe("SplitProps Props", () => { expect(otherProps.id).toBe("input"); expect(Object.keys(otherProps).length).toBe(1); }); + test("SplitProps with keys shared across groups assigns to first group only", () => { + // A key listed in more than one group must belong to the first group that + // lists it, for both plain-object and proxy (store/props) sources. + const check = (a: any, b: any, rest: any) => { + expect(a.b).toBe(2); + expect("b" in a).toBe(true); + expect(Object.keys(a).sort()).toEqual(["a", "b"]); + + expect(b.b).toBeUndefined(); + expect("b" in b).toBe(false); + expect(Object.keys(b)).toEqual(["c"]); + expect({ ...b }).toEqual({ c: 3 }); + + expect({ ...rest }).toEqual({}); + }; + + const plain = splitProps({ a: 1, b: 2, c: 3 }, ["a", "b"], ["b", "c"]); + check(plain[0], plain[1], plain[2]); + + createRoot(() => { + const [state] = createStore({ a: 1, b: 2, c: 3 }); + const proxied = splitProps(state, ["a", "b"], ["b", "c"]); + check(proxied[0], proxied[1], proxied[2]); + }); + }); test("SplitProps returns same prop descriptors", () => { const inProps = { a: 1,