Интерфейс или тип в typescript? Что использовать?
Вам нужно знать различие между типом и интерфейсом, чтобы уметь правильно выбрать и использовать.
Книга — Эффективный TypeScript: 62 способа улучшить код.
ПРАВИЛО 13. Знайте разницу между type и interface
Если вы хотите определить именованный тип в TypeScript, то у вас есть два варианта:
type TState =
interface IState
(Также можно использовать class, но он относится к понятиям среды выполнения JavaScript и тоже вводит значение.
Что же вам следует использовать, type или interface ? Граница между этими вариантами с течением времени размылась настолько, что в некоторых ситуациях можно использовать и то и другое. Обратите внимание на оставшиеся различия между ними и следуйте постоянству применения того или другого в конкретных ситуациях. Еще вам нужно знать, как прописать один и тот же тип при помощи любого из этих способов. Это поможет легче воспринимать код TypeScript, использующий их.
Сперва рассмотрим сходства: типы State , указанные выше, являются практически неотличимыми друг от друга. Если вы определите значение IState либо TState с дополнительным свойством, то ошибки в результате будут идентичными:
const wyoming: TState = < name: 'Wyoming', capital: 'Cheyenne', population: 500_000 // ~~~~~~~ Тип не может быть назначен для типа 'TState'. // литерал может определять только известные // свойства, а 'population' не существует в типе // 'TState'. >;
Вы можете использовать сигнатуру индекса и для interface , и для type :
type TDict = < [key: string]: string >; interface IDict
Также можно определить типы функций в обоих случаях:
type TFn = (x: number) => string; interface IFn < (x: number): string; >const toStrT: TFn = x => '' + x; // ok const toStrI: IFn = x => '' + x; // ok
Псевдоним типа выглядит более естественно для этого простейшего типа функции, но если тип будет иметь еще и свойства, тогда декларация будет выглядеть иначе:
type TFnWithProperties = < (x: number): number; prop: string; >interface IFnWithProperties
Этот синтаксис легче запомнить, зная, что в JavaScript функции являются вызываемыми объектами.И псевдонимы типов, и интерфейсы могут быть обобщенными:
type TPair = < first: T; second: T; >interface IPair
interface может расширять type (с некоторыми оговорками, упомянутыми ниже) и наоборот:
interface IStateWithPop extends TState < population: number; >type TStateWithPop = IState & < population: number; >;
Снова типы оказались идентичными. Оговорка заключается в том, что interface не может расширять сложные типы вроде типов объединений. Если вам нужно именно это, придется использовать type и & . Класс может реализовывать как interface , так и простой тип:
class StateT implements TState < name: string = ''; capital: string = ''; >class StateI implements IState
Так в чем же отличия? Одно вы уже видели: существуют типы объединения, но не существует интерфейсов объединения:
type AorB = 'a' | 'b';
Расширение типов объединений может быть весьма полезно. Если у вас есть раздельные типы для переменных Input и Output и отображения из имени в переменную:
type Input = < /* . */ >; type Output = < /* . */ >; interface VariableMap
тогда может понадобиться тип, приписывающий переменной имя. Например:
type NamedVariable = (Input | Output) & < name: string >;
Этот тип не может быть выражен через interface . В целом Type имеет больше возможностей, чем interface . Он может выступать в качестве объединения, а также пользоваться более продвинутыми возможностями вроде отображения или условных типов.Помимо этого, он может более ясно выражать кортежи и типы массивов:
type Pair = [number, number]; type StringList = string[]; type NamedNums = [string, . number[]];
Вы можете выразить что-либо подобное кортежу, используя interface:
interface Tuple < 0: number; 1: number; length: 2;>const t: Tuple = [10, 20]; // ok
Но это неудобно и отбрасывает методы кортежа, такие как concat . Лучше использовать type .Тем не менее у interface есть некоторые возможности, отсутствующие у type . Одна из них — это то, что interface может быть дополнен. Возвращаясь к примеру со State , вы могли бы добавить поле population другим способом:
interface IState < name: string; capital: string; >interface IState < population: number; >const wyoming: IState = < name: 'Wyoming', capital: 'Cheyenne', population: 500_000 >; // ok
Это называется объединением деклараций. Вы наверняка встречали его ранее. Главным образом оно используется с файлами деклараций типов. Для его поддержки уместно использовать interface , поскольку в декларациях типов могут быть пропуски, которые должны заполнять пользователи. TypeScript использует слияние, чтобы получать разные типы для разных версий стандартной библиотеки JavaScript. Интерфейс Array , к примеру, определен в lib.es5.d.ts . По умолчанию — это все, что вы получаете. Однако если вы добавите ES2015 к записи lib вашего tsconfig.json , то TypeScript также включит lib.es2015.d.ts . Это добавляет (посредством слияния) еще один интерфейс Array с дополнительными методами вроде find , характерными для ES2015 .
В итоге вы получаете общий тип Array , богатый методами. Слияние поддерживается в обычном коде так же, как декларации. Если же вам важно, чтобы никто не мог в дальнейшем дополнять тип, то используйте type . Вернемся к вопросу выбора между type и interface . Для сложных типов выбора у вас нет: необходимо использовать псевдоним типа. Но что насчет более простых типов объектов, которые могут быть представлены и другим путем? Чтобы ответить на этот вопрос, вам следует учитывать согласованность и возможное дополнение. Если вы работаете с кодом, который постоянно использует interface , то придерживайтесь interface . Если же в нем применяется type , используйте type .В проектах, не имеющих установленного стиля, вам следует поразмыслить над возможностью дополнения. Если вы опубликуете декларации типов для API , пользователям будет удобно вставлять новые поля через interface при изменении API . Однако для типа, который используется внутри проекта, слияние деклараций может оказаться ошибкой, поэтому отдайте предпочтение type .
Также советую прочитать:
Книга — Профессиональный TypeScript. Разработка масштабируемых JavaScript-приложений
Cтр 119. Глава — Интерфейсы
Также хорошо описывает различие между типом и интерфейсом и что где использовать.
Книга — TypeScript быстро
Cтр. 56 Глава — Базовые и пользовательские типы
Описывает различие между классом, типом и интерфейсом.
TypeScript: Сравнение Типа и Интерфейса
TypeScript, мощная надстройка над JavaScript, завоевал популярность среди разработчиков благодаря сложной системе типизации. Он предлагает два способа определения форм данных: типы и интерфейсы. Но как сделать выбор между ними? Знание тонких различий и вариантов использования очень важно для эффективной разработки. В статье мы рассмотрим типы и интерфейсы, изучим их ключевые различия и практические случаи использования, чтобы вы могли принять взвешенное решение о том, когда использовать каждый из них.
Ключевые моменты
- Понимание различий между типами и интерфейсами TypeScript очень важно для принятия обоснованных решений при разработке.
- Типы предпочтительнее использовать для примитивных значений, типов объединения/пересечения, функций и кортежей, в то время как интерфейсы обеспечивают лучшие сообщения об ошибках и производительность проверки типов.
- Выбор между ними должен основываться на личных предпочтениях, удобстве чтения и требованиях проекта.
Понимание типа и интерфейса TypeScript
В TypeScript для определения форм данных можно использовать либо типы, либо интерфейсы. Оба варианта имеют свои уникальные особенности, и понимание их различий является основополагающим для принятия обоснованного решения. Если типы используются для определения типов данных переменных, то интерфейсы определяют синтаксис классов, свойств, методов и событий.
Интерфейсы могут быть расширены дополнительными функциями после их первоначального объявления, что отличает их от типов и псевдонимов/алиасов типов в TypeScript.
Типы TypeScript
Типы TypeScript используются для определения типов данных переменных, включая встроенные типы, типы, определяемые пользователем, и дополнительные возможности, такие как псевдонимы типов. Основными типами в TypeScript являются string , boolean и number .
В TypeScript псевдоним типа позволяет изменить обозначение типа, не определяя новый тип. Объединённые типы могут быть объявлены только с помощью ключевого слова type . Такой подход предоставляет уникальные возможности, недоступные в других языках, особенно при работе с интерфейсами псевдонимов типов.
С другой стороны, типы кортежей позволяют объявить массив с фиксированным количеством элементов, причём каждый элемент имеет свой собственный тип данных. Интересно, что кортежи могут быть объявлены с помощью типов только в TypeScript.
Интерфейсы TypeScript
Интерфейсы в TypeScript представляют собой контракт, определяющий требования, которым должен удовлетворять объект. Они определяют синтаксис, которого должен придерживаться каждый объект. Компонентами интерфейса в TypeScript являются его свойства, методы и события.
Оптимальные процедуры выбора между типами и интерфейсами в TypeScript включают учёт личных предпочтений и удобочитаемости, оценку контекста и осмысление эффекта производительности.
Ключевые различия между типами и интерфейсами
Хотя типы и интерфейсы имеют ряд общих черт, между ними существуют и ключевые различия, например:
- работа с примитивными типами
- объединение и пересечение типов
- слияния объявлений
- типы функции и кортежа
Осознание этих различий необходимо для выбора подходящего инструмента для работы и оптимизации разработки на TypeScript.
Примитивные типы
Одним из ключевых различий между типами и интерфейсами является работа с примитивными типами. Типы могут использоваться с примитивными типами, такими как тип string , в то время как интерфейсы не могут использоваться с примитивными типами.
Псевдоним примитивного значения можно получить только с помощью типов, поэтому они являются рекомендуемым выбором для определения примитивных типов.
Объединение и пересечение типов
Ещё одно различие между типами и интерфейсами заключается в том, как они относятся к объединению и пересечению типов. Объединение типов может быть объявлено только с помощью ключевого слова type , а ключевое слово interface в данном контексте не применяется. Такой подход обеспечивает уникальные возможности, недоступные в других языках. Пересечение типов, напротив, создаётся с помощью оператора and в TypeScript.
Хотя интерфейсы могут комбинироваться, образуя объединение типов, они не поддерживают пересечение типов, что делает объединение типов более универсальным и выразительным в подобных ситуациях.
Слияние и расширение объявлений
Слияние объявлений — ключевое различие между интерфейсами и типами. Интерфейсы с одинаковыми именами не должны быть объявлены в одной области видимости. Это приводит к слиянию их объявлений, что может привести к неожиданным ошибкам.
Однако псевдонимы типов объединяют свойства, не приводя к ошибкам. Слияние объявлений может быть полезно для расширения определений типов сторонних библиотек, что делает интерфейсы ценным инструментом в таких сценариях.
Типы функции и кортежа
И типы, и интерфейсы могут разграничивать типы функций, но для наглядности и расширенных возможностей, таких как условные и объединительные типы, предпочтение отдаётся типам. Кортежи могут быть определены только с помощью ключевого слова type .
Как и в случае с примитивными типами, типы имеют преимущество перед интерфейсами при определении типов функций и кортежей, благодаря своей большей гибкости и выразительности.
Практические случаи использования типов и интерфейсов
Типы и интерфейсы имеют практическое применение в различных аспектах разработки на TypeScript. В зависимости от конкретной ситуации один из них может быть более подходящим, чем другой.
Мы рассмотрим некоторые часто встречающиеся случаи использования, включая объектно-ориентированное программирование, сложные структуры данных, интеграцию сторонних библиотек, и определим, что лучше подходит — типы или интерфейсы.
Объектно-ориентированное программирование
В объектно-ориентированном программировании интерфейсы лучше подходят благодаря их способности расширять классы и поддерживать наследование. Это делает интерфейсы идеальным выбором при работе с парадигмами объектно-ориентированного программирования, поскольку они обеспечивают более структурированный подход и согласованность производных классов.
Комплексные структуры данных
При работе со сложными структурами данных, благодаря поддержке объединений, пересечений и кортежей, множественные типы, в том числе объектные, часто оказываются более гибкими и выразительными. Они позволяют разработчикам создавать сложные и многократно используемые структуры данных, которые могут адаптироваться к различным сценариям. С помощью сопоставленных типов эта гибкость ещё более повышается, позволяя осуществлять ещё более мощные манипуляции с типами.
Хотя интерфейсы могут использоваться и для более простых структур данных и обеспечивают повышенную удобочитаемость и удобство сопровождения, типы, как правило, являются предпочтительным выбором для более сложных структур данных.
Интеграция со сторонними библиотеками
Интерфейсы полезны для интеграции со сторонними библиотеками благодаря возможности слияния объявлений, о чем говорилось ранее в разделе Слияние и расширение объявлений . Эта возможность позволяет разработчикам настраивать определение типа сторонней библиотеки в соответствии с требованиями конкретного проекта.
При работе со сторонними библиотеками интерфейсы могут служить мощным средством обеспечения безопасности типов, сокращения времени разработки и повышения читаемости кода.
Учёт производительности и обработки ошибок
Важными аспектами при выборе между типами и интерфейсами являются производительность и обработка ошибок. Хотя влияние использования типов на производительность по сравнению с интерфейсами минимально, интерфейсы обеспечивают более качественные сообщения об ошибках и проверку типов благодаря своей способности обнаруживать конфликты и выбрасывать ошибки при расширении.
Интерфейсы также являются более гибкими, чем типы, поскольку определяющие интерфейс элементы могут быть расширены и изменены без нарушения функциональности интерфейса.
Проверка типа и сообщения об ошибках
Интерфейсы обнаруживают конфликты и выдают ошибки при расширении, в то время как псевдонимы типов объединяют свойства без ошибок. Такое поведение позволяет улучшить сообщения об ошибках при проверке типов с помощью интерфейсов, поскольку они могут точно определить потенциальные проблемы с интерфейсом или псевдонимом типа.
В отличие от этого, псевдонимы типов могут не уловить некоторые конфликты, что может привести к неожиданному поведению и затруднить выявление первопричины проблемы.
Влияние на производительность
Несмотря на отсутствие заметной разницы в производительности между типами и интерфейсами в TypeScript, стоит отметить, что интерфейсы могут обеспечить более быструю проверку типов благодаря кэшированию по имени. Это преимущество в производительности может быть несущественным в небольших проектах, но оно может иметь значение в больших кодовых базах TypeScript со сложной иерархией типов.
Интерфейсы также могут обеспечить более организованный способ определения типов, поскольку их можно группировать.
Лучшие практики выбора между типами и интерфейсами
Выбор между типами и интерфейсами в конечном итоге зависит от личных предпочтений, удобства чтения и оценки конкретного случая использования. Хотя существуют некоторые общие рекомендации и лучшие практики, окончательное решение должно основываться на уникальных требованиях вашего TypeScript-проекта и предпочтениях вашей команды разработчиков.
Личные предпочтения и удобочитаемость
При выборе типов и интерфейсов разработчики должны учитывать свои личные предпочтения и читаемость кода. Мнения о том, какой из них более читабелен или элегантен, могут быть различными, в зависимости от индивидуальных особенностей и практики кодирования.
Очень важно найти баланс между личными предпочтениями и потребностями проекта, чтобы выбранный подход обеспечивал наилучшую читаемость и удобство сопровождения для всей команды.
Оценка ситуации
Перед выбором типа или интерфейса необходимо провести тщательную оценку ситуации и сценариев использования. Объектно-ориентированное программирование, сложные структуры данных, интеграция библиотек сторонних разработчиков — все это факторы, которые необходимо учитывать при принятии решения, включая выбор подходящего типа объекта.
Рассмотрев эти факторы и оценив плюсы и минусы каждого подхода, разработчики смогут сделать осознанный выбор, наиболее полно отвечающий потребностям их TypeScript-проекта.
Подводя итоги
В заключение следует отметить, что типы и интерфейсы TypeScript — это мощные инструменты, помогающие разработчикам создавать чистый, эффективный и поддерживаемый код. Несмотря на некоторое сходство, их ключевые различия и варианты использования делают каждый из них более подходящим для конкретных сценариев. Понимая эти различия и применяя лучшие практики, разработчики смогут использовать весь потенциал системы типов TypeScript, что приведёт к созданию более надёжных и масштабируемых проектов.
Приступая к изучению TypeScript, помните об этих различиях и выбирайте подходящий инструмент для работы. Воспользуйтесь возможностями системы типов TypeScript и позвольте ей поднять ваш опыт разработки на новую высоту.
Часто задаваемые вопросы
Что лучше использовать в TypeScript — интерфейс или тип
Интерфейсы следует использовать для слияния деклараций и объектно-ориентированного стиля наследования. Типы лучше подходят для работы с функциями и сложными типами.
В чем разница между типом и интерфейсом в TypeScript
Типы в TypeScript более гибкие и могут определять примитивы, пересечения, объединения, кортежи или различные типы данных, а интерфейсы используются для описания формы объекта. Типы используют ключевое слово type для создания нового типа, а интерфейсы — ключевое слово interface для объявления интерфейса.
Когда нужно использовать интерфейс в TypeScript
Интерфейсы в TypeScript следует использовать для проверки структуры объекта, передачи объектов в качестве параметров и создания объекта. Это целесообразно, поскольку интерфейсы обеспечивают безопасность типов, что облегчает отладку и читаемость.
Могут ли типы работать с примитивными типами
Да, типы могут использоваться с примитивными типами, что делает их полезным инструментом для структурирования данных. Однако интерфейсы не могут быть использованы подобным образом.
Разница между Type и Interface в TypeScript
Казалось бы, такие похожие, на первый взгляд сущности в TypeScript, использование которых иногда пересекается, однако это совсем не так. В данной статье хочу рассмотреть различия между этими двумя сущностями в TypeScript.
Если Вам лень читать, то можете сразу посмотреть видео на данную тему:
Ну а если не лень, то продолжаем 🙂
1. Interface для объектов, а Type для различных типов
Если мы рассмотрим вариант использования этих сущностей для объектов, то в ряде случаев они взаимно заменяемы. Рассмотрим пример:
interface Interface1 < name: string; >type Type1 =
В данном случае нет особой разницы, что использовать. Оба эти варианта подходят.
Однако, если мы будем говорить не об объектах, а о других сущностях, то тут не всё так однозначно. Для таких случаев мы должны использовать Type. Вот пара примеров:
type Type2 = (prop: string) => string; type Type3 = string;
2. Расширение (extends) interface
Для interface существует такая функциональность, как расширение. Представим простой interface Animal, который будет обозначать животного:
interface Animal
У объекта, который реализует этот interface будет одно свойство — name. По сути, при желании мы можем назвать любое животной каким-то именем, так что это вполне оправдано.
Теперь рассмотрим расширение данного interface.
interface Dog extends Animal < bark: () =>void; >
В данном случае мы создаём Interface Dog, который создаёт более конкретный тип животных — собак. И в нём мы реализуем метод bark — лай. Поскольку не все животные лают, а только собаки, то этот метод — специфическое свойство.
И давайте используем этот interface для создания объекта:
const dog: Dog = < name: 'Бобик', bark: () =>console.log('Гав') >
Как вы увидели из данного примера, interface имеет возможность создания повых interface на основе предыдущих.
3. Реализация (implements) interface
Поскольку interface — это сущность из ООП, то мы можем использовать её по назначению. Вот пример реализации:
interface Human < name: string; >class Woman implements Human < sex: string = 'woman'; name: string; constructor(name: string) < this.name = name; >>
Тут мы создали interface Human, который обозначает человека. И мы создаём class Woman. В данном контексте ясно, что Human не должен быть class, ибо люди либо мужчины, либо женщины. В то же время, interface не ограничивает нас в множественном наследовании. Мы могли создать ещё несколько interface для class Woman.
В случае с type такое невозможно, так как они не связаны напрямую с ООП.
Вывод
Исходя их всего описанного выше, хотя эти сущности и аналогичны на первый взгляд, однако это совсем не так. Используйте interface и type в соответствие с вашими задачами.
В чем отличие type и interface. В каких случаях что использовать?
Если вдруг кто придет сюда в 2020 — эта таблица вредная, ищите другую. Про «способности» тут ваще огонь. В каких-то моментах типы могут больше, чем интерфейсы. https://stackoverflow.com/questions/37233735/types.
Привет! Грубо говоря, интерфейс лишь описывает функциональность. А класс, который реализует этот интерфейс, должен конкретно функциональность определить. Например:
interface IVegetable
А конкретный класс:
class Tomato implements IVegetable < name: string = 'Tomato'; getCalories() < return 18; >>
Type — это лишь типизация какой-то переменной, как правило, нестандартной, Например, мы хотим определить тип, который будет описывать степень готовности стейков:
type SteakRoast = ‘medium’ | ‘rare’ | ‘welldone’;
Таким образом, мы можем присвоить переменной типа SteakRoast только эти предопределённые значения, а иначе Typescript заорёт из-за несоответствия типа.
