Я видел связанные вопросы, такие как Вот этот, но все они предполагают, что разница между классами и интерфейсами заключается в том, что классы могут быть созданный, а интерфейсы - нет. Однако возьмем, к примеру, @types/google.maps. Например:
declare namespace google.maps {
class Map extends google.maps.MVCObject {
constructor(mapDiv: HTMLElement, opts?: google.maps.MapOptions);
controls: google.maps.MVCArray<any>[];
data: google.maps.Data;
fitBounds(
bounds: google.maps.LatLngBounds|google.maps.LatLngBoundsLiteral,
padding?: number|google.maps.Padding): void;
// ...
}
}
declare namespace google.maps {
interface MapType {
alt: string|null;
getTile(
tileCoord: google.maps.Point|null, zoom: number,
ownerDocument: Document|null): Element|null;
maxZoom: number;
minZoom: number;
name: string|null;
projection: google.maps.Projection|null;
radius: number;
releaseTile(tile: Element|null): void;
tileSize: google.maps.Size|null;
}
}
declare namespace google.maps {
interface MapTypeControlOptions {
mapTypeIds?: (string)[]|null;
position?: google.maps.ControlPosition|null;
style?: google.maps.MapTypeControlStyle|null;
}
}
declare namespace google.maps {
class MapTypeRegistry extends google.maps.MVCObject {
set(id: string, mapType: any): void;
}
}
declare namespace google.maps {
interface MapsEventListener {
remove(): void;
}
}
declare namespace google.maps {
interface WebglCameraParams extends google.maps.CameraParams {
lat: number;
lng: number;
}
}
И интерфейсы, и классы:
Где-то в коде Google Maps на самом деле есть класс как для class
, определенных здесь, так и для interface
, определенных здесь. Похоже, что определения классов предназначены для того, что может создать пользователь, а не для того, что библиотека может создать внутри (интерфейсы).
Итак, каковы более глубокие различия между интерфейсами и классами в этих контекстах? Мне нравится то, что говорит другой ответ, что классы обычно являются конструируемыми, но эти классы явно не создаются напрямую. Они представляют другие классы. Но интерфейсы представляют и другие классы. Так что я в замешательстве.
Я имею в виду, что это не буквальныйclass X { }
в JS, это определено в машинописном тексте, как видно из незаполненных методов. Литеральный класс определен в библиотеке карт Google.
Обратите внимание, что вы смотрите на файл .d.ts
(о чем свидетельствует часть @types
. Он никогда не будет содержать никакого реального кода, только определения типов для обычного файла JS. В реальном проекте машинописи вы обнаружите, что классы имеют полный определение, в то время как интерфейсы по-прежнему доступны только для определений.
Я понимаю. Вот почему я спрашиваю, почему они определили их как классы, а не интерфейсы.
(от ваш комментарий):
I'm asking why they defined them as classes and not interfaces.
Между type
, interface
и class
есть совпадения (вы это прекрасно знаете, но мне нужно с чего-то начинать :-)) , но class
делает три вещи, а не только одну вещь, которую сделали бы interface
или type
. Давайте рассмотрим более простой пример:
declare namespace example1 {
class Example1 {
a: string;
constructor(a: string);
static method(): void;
}
}
Тот:
Example1
, который описывает экземпляры.Example1
, которая ссылается на функцию-конструктор для этих экземпляров. (Это не привязка Создайте, она просто говорит, что она есть.)typeof Example1
), который является типом функции-конструктора.Если вы хотите написать то же самое без class
, вам придется написать каждую из этих трех вещей самостоятельно, например, example2
здесь:
declare namespace example2 {
// Define the type for instances
interface Example2 {
a: string;
}
// Define that there is a binding for the constructor function
let Example2: { //
new (a: string): Example2; // Define the type for the constructor function
method(): void; //
}; //
}
Вы даже можете пойти дальше и объявить именованный тип для функции-конструктора:
declare namespace example3 {
// Define the type for instances
interface Example3 {
a: string;
}
// Define the type for the constructor function
interface Example3Constructor {
new (a: string): Example3;
method(): void;
}
// Define that there is a binding for the constructor function
let Example3: Example3Constructor;
}
(Это то, что lib.es5.d.ts
делает, скажем, для Array
, за исключением того, что вместо var
используется let
.)
Как всегда, когда есть несколько способов сделать что-то, некоторые люди сделают это одним способом, другие - другим, но есть некоторый аргумент в пользу использования class
, когда он описывает все части, которые вы пытаетесь описать сразу.
Map
из этих определений (и я делал это много раз), и я ожидаю, что смогу создать экземплярMapTypeRegistry
(хотя я не могу сказать, что у меня есть). (Очевидно, что у вас должны быть объекты среды выполнения для резервного копирования определений типов.)