-
Notifications
You must be signed in to change notification settings - Fork 193
feat(mergeProps): utility to merge component props and global config #645
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,38 @@ | ||||||||||||||||||||||||||||||||||||||||
import classNames from 'classnames'; | ||||||||||||||||||||||||||||||||||||||||
import { isPlainObject } from 'is-plain-object'; | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1
to
+2
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 修正 -import { isPlainObject } from 'is-plain-object';
+import isPlainObject from 'is-plain-object'; 如前所述, 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
function mergeClassNames<T>(classNamesA: T, classNamesB: T): T { | ||||||||||||||||||||||||||||||||||||||||
const result = { ...classNamesA }; | ||||||||||||||||||||||||||||||||||||||||
Object.keys(classNamesB).forEach(key => { | ||||||||||||||||||||||||||||||||||||||||
result[key] = mergeClassName(classNamesA[key], classNamesB[key]); | ||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||
return result; | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+4
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
当 -function mergeClassNames<T>(classNamesA: T, classNamesB: T): T {
- const result = { ...classNamesA };
- Object.keys(classNamesB).forEach(key => {
+function mergeClassNames<T extends Record<string, any>>(
+ classNamesA: T = {} as T,
+ classNamesB: T = {} as T,
+): T {
+ const result: Record<string, any> = { ...classNamesA };
+ Object.keys(classNamesB || {}).forEach(key => {
result[key] = mergeClassName(classNamesA[key], classNamesB[key]);
});
- return result;
+ return result as T;
} 这样可兼容首参缺失场景,并补全类型。 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
function mergeClassName(classNameA?: any, classNameB?: any): string { | ||||||||||||||||||||||||||||||||||||||||
if (typeof classNameA === 'object' || typeof classNameB === 'object') { | ||||||||||||||||||||||||||||||||||||||||
return mergeClassNames(classNameA, classNameB); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
return classNames(classNameA, classNameB); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||
export default function mergeProps<T>(...list: T[]): T { | ||||||||||||||||||||||||||||||||||||||||
if (list.length > 2) { | ||||||||||||||||||||||||||||||||||||||||
return mergeProps(list[0], mergeProps(...list.slice(1))); | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
const result: T = { ...list[0] }; | ||||||||||||||||||||||||||||||||||||||||
list[1] && | ||||||||||||||||||||||||||||||||||||||||
Object.keys(list[1]).forEach(key => { | ||||||||||||||||||||||||||||||||||||||||
if (key === 'className') { | ||||||||||||||||||||||||||||||||||||||||
result[key] = classNames(result[key], list[1][key]); | ||||||||||||||||||||||||||||||||||||||||
} else if (key === 'classNames') { | ||||||||||||||||||||||||||||||||||||||||
result[key] = mergeClassNames(result[key], list[1][key]); | ||||||||||||||||||||||||||||||||||||||||
} else if (isPlainObject(list[1][key])) { | ||||||||||||||||||||||||||||||||||||||||
result[key] = mergeProps(result[key], list[1][key]); | ||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||
Comment on lines
+26
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 递归合并时基对象可能为 - } else if (isPlainObject(list[1][key])) {
- result[key] = mergeProps(result[key], list[1][key]);
+ } else if (isPlainObject(list[1][key])) {
+ result[key] = mergeProps(result[key] ?? {}, list[1][key]); 若 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||
result[key] = list[1][key] ?? result[key]; | ||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||
return result; | ||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import mergeProps from '../src/mergeProps'; | ||
|
||
test('merge className', () => { | ||
expect(mergeProps({ className: 'foo' }, { className: 'bar' })).toEqual({ | ||
className: 'foo bar', | ||
}); | ||
}); | ||
|
||
test('merge classNames', () => { | ||
expect( | ||
mergeProps( | ||
{ | ||
classNames: { | ||
body: 'bam', | ||
footer: 'foo', | ||
}, | ||
}, | ||
{ | ||
classNames: { | ||
footer: 'bar', | ||
header: 'boo', | ||
}, | ||
}, | ||
), | ||
).toEqual({ | ||
classNames: { | ||
body: 'bam', | ||
footer: 'foo bar', | ||
header: 'boo', | ||
}, | ||
}); | ||
}); | ||
|
||
test('merge style', () => { | ||
expect( | ||
mergeProps( | ||
{ | ||
style: { | ||
background: '#000', | ||
color: '#666', | ||
}, | ||
}, | ||
{ | ||
style: { | ||
background: '#fff', | ||
}, | ||
}, | ||
), | ||
).toEqual({ | ||
style: { | ||
background: '#fff', | ||
color: '#666', | ||
}, | ||
}); | ||
}); | ||
|
||
test('merge boolean prop', () => { | ||
expect( | ||
mergeProps( | ||
{ | ||
disabled: true, | ||
loading: false, | ||
}, | ||
{ | ||
disabled: false, | ||
}, | ||
), | ||
).toEqual({ | ||
disabled: false, | ||
loading: false, | ||
}); | ||
}); | ||
|
||
test('merge number prop', () => { | ||
expect( | ||
mergeProps( | ||
{ | ||
value: 1, | ||
}, | ||
{ | ||
value: 2, | ||
}, | ||
), | ||
).toEqual({ | ||
value: 2, | ||
}); | ||
}); | ||
|
||
test('merge non-plain object prop', () => { | ||
const dateObj = new Date(); | ||
const urlObj = new URL('https://example.com/'); | ||
expect( | ||
mergeProps( | ||
{ | ||
value: dateObj, | ||
}, | ||
{ | ||
value: urlObj, | ||
}, | ||
), | ||
).toEqual({ | ||
value: urlObj, | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is-plain-object
需要默认导入,否则运行时会是undefined
is-plain-object
采用 CommonJS 导出方式(module.exports = fn
),在 ESM/TS 中通常通过默认导入获得函数实例。当前包以命名导入形式引用,将导致isPlainObject
为undefined
,进而在mergeProps
中触发运行时异常。请在
src/mergeProps.ts
内改为默认导入,或在此处添加@types/is-plain-object
并更新导入方式。参考补丁见下方代码评论。🤖 Prompt for AI Agents