lukeed/clsxPublic

A tiny (239B) utility for constructing `className` strings conditionally.

Conditional keys that return undefined show up as "undefined" as a result

KM

Hello!

We use Material UI to handle classNames within the solution and there are instances where we rely on Components passing down certain classes to child components and those child components use clsx to conditionally showcase certain styling, however, those instances are not always defined and when we do not handle undefined ourselves, it results in "undefined" as a class within the element. For example:

```javascript const classes = { apple: undefined, }

clsx({ [classes.apple]: true }) // returns the string "undefined" clsx({ [classes.banana]: true }) // returns the string "undefined" ```

My expectation would be that clsx checks for `undefined` in the object keys and when `undefined` exists, don't include that as part of the result.

  1. LU

    Your expectation is semantically incorrect. Take this further-boiled-down example:

    ```js let aaa = undefined; let bbb = { [aaa]: 123 }; //=> { undefined: 123 }

    for (let key in bbb) { console.log(key, typeof key); } //=> undefined string ```

    You cannot have `undefined` – the value type – as an object key. It's immediately converted into a string. Your `[dynamic key]` is evaluated as the key's value, so by the time your `bbb`-equivalent object is evaluated, it's as if you had written this directly:

    ```js let ccc = { undefined: 123 }; // a key named "undefined" ```

    ---

    Because this is the language's mechanics, this matches `classnames` behavior.

    Additionally, this is not how dynamic objects were meant to be used in `classnames` / `clsx` at all. The patten came about because of CSS modules:

    ```js import * as styles from './index.css'; // or: import styles from './index.css';

    // the CSS is imported as an object // whose keys are the original classes, // AKA, what you wrote in your CSS source, // mapping to the rewritten, unique class names, // as determined by your localidentname rules console.log(styles); //=> { //=> apple: "apple__Apple_123", //=> banana: "banana__Banana_a2g", //=> } // OR, in prod: //=> { //=> apple: "a1x", //=> banana: "b2g", //=> }

    // Then you use them in your component styles. // Through type analysis (because it's all statically known), // you can get lint and/or build-time errors if trying to access // keys that don't exist <div class={ cx({ [styles.apple]: props.isApple }) }> <p class={ styles.bold }> Throws error ^^ because "bold" key is known not to exist </p> </div> ```

    Hope that helps~!

  2. lukeedclosed5 years ago on GitHub

  3. lukeedreferenced this in Supporting unwanted undefined in object #613 years ago on GitHub