// Затипизировать
// Два объекта с использованием воды/энергии.
const electricityUserData = {
readings: 95,
units: "kWt",
mode: "double",
};
const waterUserData = {
readings: 3,
units: "m3",
};
// Тарифы за энергию.
const elRate: number = 0.45;
const wRate: number = 2;
// Массив с счетами за энергрию/воду.
const monthPayments: number[] = [0, 0]; // [electricity, water]
// Ф-я вычисляет месячную плату и записывает зн-я в monthPayments.
const calculatePayments = (
elData: {
readings: number;
units: string;
mode: string;
},
wData: {
readings: number;
units: string;
},
elRate: number,
wRate: number
): void => {
if (elData.mode === "double" && elData.readings < 50) {
monthPayments[0] = elData.readings * elRate * 0.7;
} else {
monthPayments[0] = elData.readings * elRate;
}
monthPayments[1] = wData.readings * wRate;
};
calculatePayments(electricityUserData, waterUserData, elRate, wRate);
// Ф-я выставляет счет.
const sendInvoice = (
monthPayments: number[],
electricityUserData: {
readings: number;
units: string;
mode: string;
},
waterUserData: {
readings: number;
units: string;
}
): string => {
const text = ` Hello!
This month you used ${electricityUserData.readings} ${electricityUserData.units} of electricity
It will cost: ${monthPayments[0]}€
This month you used ${waterUserData.readings} ${waterUserData.units} of water
It will cost: ${monthPayments[1]}€`;
return text;
};
console.log(sendInvoice(monthPayments, electricityUserData, waterUserData));
.
- Иногда наши литеральные типы могут содержать много значений, иногда мы хотим их переиспользовать в разных частях кода. В таких ситуациях хотелось бы вынести такой код в отдельную сущность по типу переменной. Этим и занимаются псевдонимы:
// Создаем псевдоним типа для использования/переиспользования далее.
type TypeAnimationTiming = "ease" | "ease-out" | "ease-in";
type TypeAnimationID = string | number;
// Типизируем аргументы ф-ии с помощью псевдонимов типов.
function createAnimation(
id: TypeAnimationID,
animName: string,
timing: TypeAnimationTiming = "ease",
duration: number
): void {}
-
Можно создавать type, который содержит описание объекта, а не только отдельные литералы. Это позволит нам указывать объектам, что они должны быть одной формы (одного формата, object shape):
-
Такие значения удобнее читать, можно переиспользовать и поместить любые типы в псевдоним. Их можно создавать внутри функций, внутри методов классов или объектов, внутри отдельных модулей и тп. Когда вам это нужно. В type можно помещать и объекты.
-
После компиляции они исчезают, так что эта возможность существует только в TS.
// Создание type
// 2 обязательных и name - необязательный
// Теперь type с именем TypeConfig можно использовать для аннотирования других объектов.
// Если они не будут соответствовать этой форме - будет ошибка.
// В свойствах объекта внутри type может быть что угодно (литералы, типы, объекты и тп.)
type TypeConfig = {
protocol: "http" | "https";
port: 3000 | 3001;
name?: string;
};
// Описываем объекты при помощи созданного типа TypeConfig
const serverConfig: TypeConfig = {
protocol: "http",
port: 3001,
};
const backupConfig: TypeConfig = {
protocol: "https",
port: 3000,
name: "store",
};
-
Нам часто приходится комбинировать типы для удобного и быстрого создания нужных нам. Иногда мы не хотим дублировать код (принцип DRY), иногда типы приходят нам из сторонней библиотеки или файла. В этих и других случаях нам понадобится оператор пересечения (&).
-
Благодаря оператору пересечения (intersection, &) мы скомбинировали два типа и получили тип ConfigWithRole. Он содержит все свойства из объединенных типов. Теперь все три type можно использовать в коде.
type TypeConfig = {
protocol: "http" | "https";
port: 3000 | 3001;
name?: string;
};
// Добавим еще один тип с ролью
type TypeRole = {
role: string;
};
// Создадим тип на основе двух предыдущих.
// Этот тип объеденит в себе все описания двух прошлых.
type TypeConfigWithRole = TypeConfig & TypeRole;
// Описываем объект с помощью пересеченных типов.
const serverConfig: TypeConfigWithRole = {
protocol: "http",
port: 3001,
role: "admin",
name: "moskit11111",
};
- В отдельный type можно выносить и описание функции:
// Тип описания ф-ии с описание входных параметров.
type TypeStartServer = (
protocol: "http" | "https",
port: 3000 | 3001
) => string;
// Импользуем тип.
const startServer: TypeStartServer = (
protocol: "http" | "https",
port: 3000 | 3001
): "Server started" => {
console.log(`Server started on ${protocol}://server:${port}`);
return "Server started";
};
-
Интерфейс - это еще один тип в TS, который позволяет синтаксически записать шаблон того , который будет создан
-
Интерфейс создается при помощи ключевого слова interface, имени (начиная с I) с большой буквы и раскрытия фигурных скобок:
-
В свойствах объекта может быть что угодно: литералы, другие типы и тд. При замене type на interface в коде ничего не сломается. Они действительно очень похожи.
// Интерфейс, описывающий объект
interface IConfig {
protocol: "http" | "https";
port: 3000 | 3001;
name?: string;
}
const serverConfig: IConfig = {
protocol: "http",
port: 3001,
name: "moskit11111",
};
const backupConfig: IConfig = {
protocol: "https",
port: 3000,
};
- Для комбинации нескольких интерфейсов и получения нового используется ключевое слово extends:
- Полученый интерфейс будет иметь все свойства указаных + можно добавлять новые внутри фигурных скобок
// Интерфейс, описывающий объект.
interface IConfig {
protocol: "http" | "https";
port: 3000 | 3001;
name?: string;
}
// Интерфейс роли.
interface IRole {
role: string;
}
// Интерфейс, наследующий св-ва у IConfig и IRole одновременно.
// Плюс можем добавить доп.
interface IConfigRole extends IConfig, IRole {
rights: "all" | "read";
}
const serverConfig: IConfig = {
protocol: "http",
port: 3001,
name: "moskit11111",
};
const backupConfig: IConfigRole = {
protocol: "https",
port: 3000,
role: "admin",
name: "acidshotgun",
rights: "all",
};
- И типы и интерфейсы могут описывать методы объектов.
// Интерфейс, описывающий объект + описали метод.
interface IConfig {
protocol: "http" | "https";
port: 3000 | 3001;
name: string;
role: "admin" | "user";
rights: "all" | "read";
// Метод с параметрами.
log: (msg: string) => void;
}
// Добавили в объект метод log.
const serverConfig: IConfig = {
protocol: "http",
port: 3001,
name: "moskit11111",
role: "admin",
rights: "all",
log: (msg: string): void => console.log(msg),
};
// Типизировали входящий аргумент для метода log.
// Если мы не знаем какой аргумент будет приходить в ф-ю, то можно написать:
// log: Function
// Но это не круто
// Всегда нужно типизировать.
const startServer = (
protocol: "http" | "https",
port: 3000 | 3001,
log: (msg: string) => void
): "Server started" => {
// Передали сообщения в метод log.
log(`Server started on ${protocol}://server:${port}`);
return "Server started";
};
// Вызываем в ф-ии еще и наш метод.
startServer(serverConfig.protocol, serverConfig.port, serverConfig.log);
- Если мы не знаем, что будет в объекте, но знаем что это будет один тип данных можно воспользоваться след синтаксисом.
// Ключи - строка, зн-е - строка.
// И тд.
interface IStyle {
[key: string]: string;
}
const style: IStyle = {
position: "absolute",
padding: "25px",
border: "1px solid black",
borderRadius: 50, // - ошибка(number)
};
- Интерфейсы и типы нужны для того, чтобы описывать объекты(пока что) - что в них будет содержаться и в каком кол-ве.
- Интерфейсы и типы немного отличаются по синтаксису.
- За счет описания структуры можно создавать интересные паттерны поведения кода в разных ситуациях.
- Главное - во время написания есть подсказки и предупреждения об ошибках для исправления во время разработки.
- Интерфейсы (Interfaces):
- Используются для описания структуры или формы объектов, классов и компонентов React.
- Применяются для типизации объектов, которые представляют собой экземпляры классов, функций, ожидающих объекты с определенной структурой.
- Часто используются для определения контракта, который объекты или классы должны соблюдать.
- Типы (Types):
- Используются для создания алиасов для существующих типов данных и определения пользовательских типов данных.
- Применяются для типизации данных, не связанных с объектами, например, для типизации переменных, алиасов, функций и т. д.
- Полезны для создания новых типов данных, которые не связаны с конкретной структурой объекта или класса.
- Соглашения:
- Используйте интерфейсы для типизации объектов, классов и компонентов.
- Используйте типы для типизации переменных, алиасов и функций.