Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions packages/solid/src/render/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<PropertyKey>();
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
Expand Down
25 changes: 25 additions & 0 deletions packages/solid/test/component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading