How do I change a field type?
I have also get this kind of issue that change field type from one to another with existing data. So as @Eyal mentioned, we can write an update hook to


export data from a field table to a variable
remove fields of all bundles
add new fields of all bundles
restore data to field table


Here is the code example

use \Drupal\field\Entity\FieldStorageConfig;
use \Drupal\field\Entity\FieldConfig;

/**
 * Change node__field_maps from string_long to string type.
 */
function mymodule_update_8XXX() {
  $database = \Drupal::database();
  $table = 'node__field_maps';
  $entity_type = 'node';
  $field_name = 'field_maps';

  $field_storage = FieldStorageConfig::loadByName($entity_type, $field_name);

  if (is_null($field_storage)) {
    return;
  }

  $rows = NULL;

  if ($database-&gt;schema()-&gt;tableExists($table)) {
    // The table data to restore after the update is completed.
    $rows = $database-&gt;select($table, 'n')
      -&gt;fields('n')
      -&gt;execute()
      -&gt;fetchAll();
  }

  $new_fields = array();

  // Use existing field config for new field.
  foreach ($field_storage-&gt;getBundles() as $bundle =&gt; $label) {
    $field = FieldConfig::loadByName($entity_type, $bundle, $field_name);
    $new_field = $field-&gt;toArray();
    $new_field['field_type'] = 'string';
    $new_field['settings'] = array();

    $new_fields[] = $new_field;
  }

  // Deleting field storage which will also delete bundles(fields).
  $new_field_storage = $field_storage-&gt;toArray();
  $new_field_storage['type'] = 'string';
  $new_field_storage['settings'] = array(
    'max_length' =&gt; 255,
    'is_ascii' =&gt; FALSE,
    'case_sensitive' =&gt; FALSE,
  );

  $field_storage-&gt;delete();

  // Purge field data now to allow new field and field_storage with same name
  // to be created. You may need to increase batch size.
  field_purge_batch(10);

  // Create new field storage.
  $new_field_storage = FieldStorageConfig::create($new_field_storage);
  $new_field_storage-&gt;save();

  // Create new fields.
  foreach ($new_fields as $new_field) {
    $new_field = FieldConfig::create($new_field);
    $new_field-&gt;save();
  }

  // Restore existing data in the same table.
  if (!is_null($rows)) {
    foreach ($rows as $row) {
      $database-&gt;insert($table)
        -&gt;fields((array) $row)
        -&gt;execute();
    }
  }

}


NOTE: Always backup DB and test code before running this code 

Other thoughts
In my case, we also have exported configures which means the field type and settings are also included in field_storage_config, field_config, entity_form_display, and entity_view_display config files. So we have to update config settings in those files as well. One easy way could be:


clone your website
delete the field and add a field with the same name again in field UI
export configures to use them in the repo
make sure the config uuid for the field and storage were not changed (change the uuid back if it was) to avoid the import potentially removing data.
import configure after DB update and clear cache again


This is code is inspired by @drugan in the post https://www.drupal.org/node/2816859