For a field of type list_text you can do the following:

$field = field_info_field('field_custom_field');
  if (empty($field)) {
    $field = array(
      'field_name' => 'field_custom_field',
      'type' => 'list_text',
      'entity_types' => array('node'),
      'locked' => TRUE,
      'settings' => array(
        'allowed_values_function' => 'node_type_get_names',
      ),
    );
    field_create_field($field);
  }

This way you can populate a select list with all available node types, or whatever your callback will return.

If you would do the same for nodereference you could do something like:

  $field = field_info_field('field_custom_field2');
  if (empty($field)) {
    $field = array(
      'field_name' => 'field_custom_field2',
      'type' => 'node_reference',
      'entity_types' => array('node'),
      'locked' => TRUE,
      'settings' => array(
         'referenceable_types_function' => 'my_node_types_function',
      ),
    );
    field_create_field($field);
  }

  function my_node_types_function() {
    return drupal_map_assoc(array_keys(node_type_get_names()));
  }

This way all node types will always be available even when more are created afterwards. Developers could also filter the node types in their callback function however they like. For fields of the 'list_text' type this setting can only be set in code, not through the interface as far as I know, so it's protected from users that don't know PHP.