DEV Community

Dan Greene
Dan Greene

Posted on

How to properly deprecate

Why would I deprecate?

Sometimes you release a function or widget with your library and you later think "wow I could have done that better." After all, if you're not looking back at your old code and thinking "who wrote this" then you're not improving as a developer.

But... you can't just delete that function in your next library release. If you did that, your consumers would get 💥 a in their build, or (if they're not using static compilation like TypeScript) the end user will get a bug in production. 🤕

So you've got to give your library's consumers some advanced notice.

How to do it

  1. Make a plan to only remove the item from your next major version (i.e. x.1.1) This is because users only expect functionality removal in major versions due to how SemVer works.
  2. In your next patch version (i.e. 1.1.x), plan to do the next steps
  3. Add a @deprecated JSDoc tag to the JSDoc comment for that function/class/component. See an example of how to do that in the JSDoc website.
  4. Since the JSDoc tag only helps developers if they have eslint-plugin-import/no-deprecated and/or eslint-plugin-deprecated-props installed, you should do the developer a favor by using console.warn when that function or property is used. I'll provide an example below.
  5. Here's the most important step: tell your consumers about the upcoming change. That means updating your release notes to explain that the item is going to be removed soon. It also means sharing it with your twitter followers, your Slack channel, dev.to, and (if your library is private) share it in your company's internal communications. Do you have to do this last step? Sure, you could skip it since the steps above will give runtime and compilation time feedback... however, why not give your users advanced heads up?

Bringing it all together

Here's how you'd deprecate a function:

/**
 * this is what you get when you trust a mouse talk show
 * @deprecated please use our new function mult instead
 * @returns {Number}
 */
export function multiply(a, b) {
  return a * b;
}
Enter fullscreen mode Exit fullscreen mode

Here's how you'd deprecate a property in a function. This is only possible in TypeScript (see source).

interface ComponentProps {
  /**
   * Some prop that is going to be removed in the future
   * @deprecated This will be removed soon in favor of colorHex
   */
  colorName?: string;
  colorHex: string;
  someOtherProp: string;
}

/**
 * Note that the @deprecated prop is used in the implementation
 * since it should still work. This does not throw a warning per se.
 */
const Component = ({ colorHex, colorName, someOtherProp }: ComponentProps) => {
  if(colorName){
    console.warn('colorName is deprecated. Please use colorHex instead');
  }
  const colorClassName = determineClassName(colorHex, colorName);
  return <div className={colorClassName}>{someOtherProp}</div>;
};
Enter fullscreen mode Exit fullscreen mode

Side note, isn't it cool that VSCode shows that colorName is deprecated by putting a strikethrough style on it?

Image description

Any questions?

Given how quickly the "developer experience" (DX) area is evolving, I'm sure there are improvements on this approach. So please comment below if you have suggestions, questions, or tips. Thanks for reading! :)

Top comments (2)

Collapse
 
betofrega profile image
Beto Frega

I like the idea of only fully deprecating not a major version down the line, but a specific amount of time... but still hiding deprecated methods behind a feature flag, so that users explicitly accept the risk.

eg.:
v1.0.1 - bad method
v1.0.2 - @deprecated
v2.x.x - hide the deprecated method under a feature flag with an ENABLE_DEPRECATED_* prefix, like ENABLE_DEPRECATED_MULTIPLY_METHOD
1 year later, v 4.x.x - method is finally removed

Collapse
 
dgreene1 profile image
Dan Greene

That feature flagging approach does seem valuable, but it also brings additional complexity. If you and your team have the time to spend on that level of fidelity, that's wonderful. In most of the places I work, you can simply remove the deprecated method in the next major version since the social contract of semantic versioning states that the author is allowed to make breaking changes in major versions.