javascript - Varför ett gränssnittargument tillåter vilken typ som helst


Jag försöker ärva baskgränssnittet IScreen som kommer att utökas med IModal, IEmbedded eller ITab, och låsa metoder så att de är specifika för ett gränssnitt. Men vad som händer är att metoden public OpenModal(modal: IModal) av någon anledning bara accepterar vilken typ som helst.

Lekplats

namespace Framework {
    "use strict";

    interface IScreen { }
    interface IModal extends IScreen { }
    interface ITab extends IScreen { }
    interface IEmbedded extends IScreen { }

    class BaseScreen implements IScreen {
        public HandleCloseEvent() {

        }
    }

    class DetailsScreen extends BaseScreen implements IModal {

    }

    class ListScreen extends BaseScreen implements IEmbedded {

    }

    class OpenerService {
        public OpenScreen(screen: IScreen) {

        }

        public OpenModal(modal: IModal) {

        }
    }

    class Controller {
        constructor(openerService: OpenerService) {

            var detailsScreen: DetailsScreen = new DetailsScreen();
            var listScreen: ListScreen = new ListScreen();

            openerService.OpenModal(212121); // Expected error
            openerService.OpenModal(listScreen); // Expected error
        }
    }
}
  • Saknar jag några kompilatorinställningar eftersom jag inte får några felmeddelanden?
  • Missförstår jag hur gränssnitt fungerar?

Svar #1

Det är så TypeScript fungerar: med strukturell typning (även kallad duck typing).

Du förklarar:

   public OpenModal(modal: IModal) {
   }

Eftersom alla dina gränssnitt är tomma, är det ekvivalent med att skriva:

   public OpenModal(modal: {}) {
   }

Denna signatur accepterar varje objekt, eftersom alla objekt är kompatibla med ett tomt objekt. 212121 är ett objekt (i JavaScript är ett nummer ett objekt). listScreen är också ett objekt.

Du kan märka att det är värdelöst att deklarera flera gränssnitt för den tomma objekttypen:

interface IScreen { }
interface IModal extends IScreen { }
interface ITab extends IScreen { }
interface IEmbedded extends IScreen { }

Här är alla dina gränssnitt likvärdiga. Det finns ingen hierarki. Du kan göra:

let a: IScreen
let b: IModal
let c: IModal = a // type '{}' ('IScreen') is compatible to type '{}' ('IModal')
let d = {}
let e: IModal = d // type '{}' is compatible to type '{}' ('IModal')

Se även:

  • Vad är strukturell typning?
  • Handboken om gränssnitt
  • Typer är strukturella