Gutenberg: how to make post categories required?

This is how:

const { select, dispatch, subscribe } = wp.data;

const getCategories = () => select( 'core/editor' ).getEditedPostAttribute( 'categories' );
let categories = getCategories();
subscribe( () => {
  const newCategories = getCategories();
  const categoriesChanged = newCategories !== categories;
  categories = newCategories;
  if ( categoriesChanged ) {
    if ( categories.length === 0 ) {
      // show notice
      dispatch( 'core/notices' ).createNotice(
        'error',
        'Please select at least one category',
        {
          id: 'xyz_notice_category',
          isDismissible: false,
        }
      );

      // Make sure post cannot be saved, by adding a save lock
      dispatch( 'core/editor' ).lockPostSaving( 'xyz_category_lock' );
    } else {
      // remove notice
      dispatch( 'core/notices' ).removeNotice( 'xyz_notice_category' );

      //remove save lock
      dispatch( 'core/editor' ).unlockPostSaving( 'xyz_category_lock' );
    }
  }
} );

So, what’s happening here?

First we get all the currently selected categories with:

select( 'core/editor' ).getEditedPostAttribute( 'categories' )

Then we subscribe to any changes in the data store. If we detect a change in the selected catergories, we check the number of selected categories. If the number is zero, we show an error message with:

dispatch( 'core/notices' ).createNotice(
  'error',
  'Please select at least one category',
  { id: 'xyz_notice_category', isDismissible: false, }
);

and we make sure that the post cannot be saved with:

dispatch( 'core/editor' ).lockPostSaving( 'xyz_category_lock' );

If the number of categories is greater then zero, we can get rid of the error message and the post lock with:

// remove notice
dispatch( 'core/notices' ).removeNotice( 'xyz_notice_category' );

//remove save lock
dispatch( 'core/editor' ).unlockPostSaving( 'xyz_category_lock' );