Вопрос: Что я не так делаю с интерфейсами?

Лучший ответ:
Что я не так делаю с интерфейсами?
Всё.
У тебя у одного интерфейса слишком много ответственностей у него и Warside какой-то есть и дамаг может принимать и умереть может.

Разделяй этот интерфейс на несколько.

namespace Health
{
    public interface IHealth
    {
        void Lose(int amount);
        void Restore(int amount);
    }
    
    public interface IMutable<out T>
    {
        T Current { get; }
    }
    
    public interface IFinal
    {
        event Action Over;
    }
}

Получается такой Health:

using System;
using UnityEngine;

namespace Health
{
    public class Health : IHealth, IFinal, IMutable<int>
    {
        public event Action Over;
        private readonly int _max;
        private const int Min = 0;

        public Health(int max)
        {
            _max = max;
            Current = _max;
        }
        
        public int Current { get; private set; }
        
        public void Lose(int amount)
        {
            SetCurrent(Current - amount);
        }

        public void Restore(int amount)
        {
            SetCurrent(Current + amount);
        }

        private void SetCurrent(int amount)
        {
            Current = Mathf.Clamp(amount, Min, _max);
            
            if (Current == Min) Over?.Invoke();
        }
        
    }
}

Health не должен быть отдельным компонентом, который будет висеть на условном рыцаре. Рыцарь будет содержать в себе этот Health, но напрямую хп ему изменять никто не будет, поэтому нужен еще один интерфейс IDamageable:
namespace Health
{
    public interface IDamageable
    {
        void ApplyDamage(int amount);
    }
}

И сам рыцарь:
using UnityEngine;

namespace Health
{
    public class Knight : MonoBehaviour, IDamageable
    {
        [SerializeField] private int _maxHealth = 100;
        private Health _health;

        private void Awake()
        {
            _health = new Health(_maxHealth);
        }

        private void OnEnable()
        {
            _health.Over += Die;
        }

        private void OnDisable()
        {
            _health.Over -= Die;
        }

        public void ApplyDamage(int amount)
        {
            _health.Lose(amount);
            Debug.Log($"Damaged, hp left - {_health.Current}");
        }

        private void Die()
        {
            Debug.Log("Died");
            Destroy(gameObject);
        }
    }
}

Теперь, чтобы нанести урон рыцарю, нужно получить компонент IDamageable и вызвать его метод ApplyDamage:
using UnityEngine;

namespace Health
{
    public class Enemy : MonoBehaviour
    {
        [SerializeField] private int _damage = 50;
        
        private void OnTriggerEnter2D(Collider2D other)
        {
            if (other.TryGetComponent(out IDamageable damageable))
            {
                damageable.ApplyDamage(_damage);
            }
        }
    }
}

Всё. Используй TryGetComponent и тогда не нужно будет делать миллион проверок является ли что-то null.
Warside твой должен висеть на рыцаре, а не на хп, поэтому делай отдельный интерфейс под этот Warside.

Худший ответ:
Котик конечно крутой, СОЛИДно объяснил тебе за все, но ты никогда так не достанешь интерфейс с объекта...
Тебе не понравилось, что интерфейс не показывется в инспекторе - так объяви gameObject 
и потом в awake доставай свой интерфейс вот так :
gameObg = GetComponent(typeof(IHealth)) as IHealth; 
а еще не нужно доставать компоненты в рантайме - пиши отдельные скрипты детекторы 

using System;
using UnityEngine;

[RequireComponent(typeof(BoxCollider))]
public class PlayerDetector : MonoBehaviour
{
    internal event Action OnPlayerEnter, OnPlayerExit, OnPlayerStay;

    protected virtual void OnTriggerEnter(Collider other)
    {
       if (OnPlayerEnter != null)
        if (IsPlayer(other.gameObject))
        {
            OnPlayerEnter.Invoke();
        }
    }
    protected virtual void OnTriggerExit(Collider other)
    {
       if (OnPlayerExit != null)
        if (IsPlayer(other.gameObject))
        {
            OnPlayerExit.Invoke();
        }
    }
    protected virtual void OnTriggerStay(Collider other)
    {
       if (OnPlayerStay!=null)
        if (IsPlayer(other.gameObject))
        {
            OnPlayerStay.Invoke();
        }
    }


    public static bool IsPlayer(GameObject ob)
    {
        if (ob.CompareTag("Player"))
            return true;

        return false;
    }
}
Метишь тегом своим рыцаря и кидаешь скрипт на объект который может наносить урон, подписываешься на OnPlayerEnter в скрипте который наносит Damage и не паришься -все безопасно