Да, есть различия, которые могут или не могут иметь значение в вашем сценарии.
Возможно, наиболее значительным является различие в том, как обрабатываются элементы с одинаковым ключом свойства, когда они присутствуют в обоих типах.
Учтите:
interface NumberToStringConverter {
convert: (value: number) => string;
}
interface BidirectionalStringNumberConverter extends NumberToStringConverter {
convert: (value: string) => number;
}
Приведенное выше extends
приводит к ошибке, поскольку интерфейс извлечения объявляет свойство с тем же ключом, что и в производном интерфейсе, но с несовместимой подписью.
error TS2430: Interface 'BidirectionalStringNumberConverter' incorrectly extends interface 'NumberToStringConverter'.
Types of property 'convert' are incompatible.
Type '(value: string) => number' is not assignable to type '(value: number) => string'.
Types of parameters 'value' and 'value' are incompatible.
Type 'number' is not assignable to type 'string'.
Однако, если мы используем типы пересечений
interface NumberToStringConverter = {
convert: (value: number) => string;
}
type BidirectionalStringNumberConverter = NumberToStringConverter & {
convert: (value: string) => number;
}
Нет ошибки вообще и далее, учитывая
declare const converter: BidirectionalStringNumberConverter;
converter.convert(0); // `convert`'s call signature comes from `NumberToStringConverter`
converter.convert('a'); // `convert`'s call signature comes from `BidirectionalStringNumberConverter`
// And this is a good thing indeed as a value conforming to the type is easily conceived
const converter: BidirectionalStringNumberConverter = {
convert: (value: string | number) =>
typeof value === 'string'
? Number(value)
: String(value)
}
Это приводит к еще одному интересному различию, interface
декларациямоткрытыНовые члены могут быть добавлены в любом месте, потому что interface
объявлений в одном и том же пространстве объявлений и с одинаковыми именами объединены .
Здесь обычно используется поведение слияния
lib.d.ts
interface Array<T> {
// map, filter, etc.
}
array-flat-map-polyfill.ts
interface Array<T> {
flatMap<R>(f: (x: T) => R[]): R[];
}
if (typeof Array.prototype.flatMap !== 'function') {
Array.prototype.flatMap = function (f) {
return this.map(f).reduce((xs, ys) => [...xs, ...ys], []);
}
}
Обратите внимание, как нет extends
условие присутствует, хотя указанные в отдельных файлах интерфейсы находятся в глобальной области видимости и объединяются по имени в одно объявление логического интерфейса, которое имеет оба набора членов.(то же самое можно сделать для объявлений в области модуля с немного отличающимся синтаксисом)
Напротив, типы пересечений, хранящиеся в объявлении type
, закрыты и не подлежат объединению.
Есть много, много различий.Вы можете прочитать больше об обеих конструкциях в TypeScript Handbook.Разделы Interfaces и Advanced Types особенно актуальны.