Skip to content

Instantly share code, notes, and snippets.

@brookback
Created July 9, 2019 10:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brookback/0f46aadcafa75d05837857b3e232dfbb to your computer and use it in GitHub Desktop.
Save brookback/0f46aadcafa75d05837857b3e232dfbb to your computer and use it in GitHub Desktop.
type ValidClass = string | number | undefined | null | ObjectClass;
type ObjectClass = {
[key: string]: boolean | undefined;
};
type ClassName = ValidClass | ValidClass[];
/**
* Easier class names management for JSX elements.
*
* Usage:
*
* ```js
<div className={classNames('some-class', 'another', ['arr', 'of', 'classes'], {
'conditional-class': this.state.someValue
})}>
```
* Note that the order of the keys in a passed object will not be explicitly
* preserved: that's up to the Javascript engine (most engines preserve key order).
*/
export default function classNames(...args: ClassName[]): string {
return args
.filter((_) => !!_) // Filter out falsiness
.map((arg) => {
const type = typeof arg;
// We can add numbers and strings as class names instantly,
// but for arrays and objects, we need to traverse.
if (type === 'string' || type === 'number') {
return arg;
} else if (Array.isArray(arg) && arg.length) {
// Recuuuurse
return classNames(...arg);
} else if (type === 'object' && arg) {
const objMap = <ObjectClass>arg;
return Object.keys(objMap)
.filter((cl) => objMap[cl])
.join(' ');
}
return '';
})
.join(' ');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment