TypeScript. Функция как тип
Как описать переменную, если в ней должна лежать функция? Как ни странно, с помощью стрелочной функции.
#typescript
Как описать переменную, если в ней должна лежать функция? Как ни странно, с помощью стрелочной функции.
#typescript
👍1🔥1
TypeScript. Кастомные типы данных
Можно создавать собственные типы данных с помощью ключевого слова
Таким же образом можно создавать сложные типы (объекты):
Свойства со знаками вопроса - необязательные.
Такой тип можно переиспользовать много раз:
Это намного удобнее, чем указывать тип сразу для переменной:
Важно: если присвоить в переменную объект, у которого будут "лишние" свойства (не описанные в типе), TypeScript выбросит ошибку.
#typescript
Можно создавать собственные типы данных с помощью ключевого слова
type
:
type Name = string;
const userName1: Name = 'John';
const userName2: Name = 'Jane';
Таким же образом можно создавать сложные типы (объекты):
type Person = {
name: string,
age: number,
nickName?: string
}
Свойства со знаками вопроса - необязательные.
Такой тип можно переиспользовать много раз:
const user1: Person = { name: 'John', age: 25, nickName: 'Zorro' };
const user2: Person = { name: 'Jane', age: 23 };
Это намного удобнее, чем указывать тип сразу для переменной:
const user3: { name: string, age: number, nickName?: string } = { name: 'Robert', age: 30 };
Важно: если присвоить в переменную объект, у которого будут "лишние" свойства (не описанные в типе), TypeScript выбросит ошибку.
#typescript
👍1🔥1
TypeScript. Классы, свойства классов
Классы в TS определяются точно так же, как в JS:
В TS мы можем объявить поля класса и указать их типы:
Есть модификаторы доступа:
-
-
-
-
Также свойствам можно указывать значения по умолчанию.
Чтобы не дублировать код свойств три раза (определение в классе, параметры конструктора и присвоение в конструкторе), можно определять их сразу в конструкторе:
Тут обязательно указывать модификаторы для каждого свойства. Все свойства, указанные таким образом автоматически присвоятся одноименным полям класса.
#typescript
Классы в TS определяются точно так же, как в JS:
class User {
}
В TS мы можем объявить поля класса и указать их типы:
class User {
name: string;
age: number = 20;
nickName: string = 'Superman';
private secret = '12345';
constructor(name: string, age: number, nickName: string) {
this.name = name;
this.age = age;
this.nickName = nickName;
}
}
Есть модификаторы доступа:
-
public
(по умолчанию все свойства публичные)-
private
(доступны только внутри текущего класса)-
protected
(доступны внутри текущего класса и его подклассов)-
readonly
Также свойствам можно указывать значения по умолчанию.
Чтобы не дублировать код свойств три раза (определение в классе, параметры конструктора и присвоение в конструкторе), можно определять их сразу в конструкторе:
class User {
constructor(
public name: string,
public age: number,
public nickName: string
) {
}
}
Тут обязательно указывать модификаторы для каждого свойства. Все свойства, указанные таким образом автоматически присвоятся одноименным полям класса.
#typescript
👍1🔥1
TypeScript. Классы, статические свойства
Для объявления статических свойств (принадлежащих классу, а не экземпляру), используется ключевое слово
Это то же самое, что и
#typescript
Для объявления статических свойств (принадлежащих классу, а не экземпляру), используется ключевое слово
static
:class User {
static secret = 12345;
}
Это то же самое, что и
class User {}
User.secret = 12345;
#typescript
👍1🔥1
TypeScript. Абстрактные классы
В TypeScript есть возможность создавать абстрактные классы - концепция из сферы полиморфизма, обеспечивающая общий интерфейс для обычных классов, наследующих от абстрактного. При этом экземпляры абстрактного класса напрямую создавать нельзя.
В абстрактном классе могут быть как обычные методы (с реализацией), так и абстрактные (без реализации, только с сигнатурой). При этом подклассы должны реализовать все заявленные абстрактные методы сами.
#typescript
В TypeScript есть возможность создавать абстрактные классы - концепция из сферы полиморфизма, обеспечивающая общий интерфейс для обычных классов, наследующих от абстрактного. При этом экземпляры абстрактного класса напрямую создавать нельзя.
abstract class User {
constructor(
public name: string,
public age: number
) {}
greet(): void {
console.log(this.name);
}
abstract getPass(): string;
}
В абстрактном классе могут быть как обычные методы (с реализацией), так и абстрактные (без реализации, только с сигнатурой). При этом подклассы должны реализовать все заявленные абстрактные методы сами.
#typescript
👍1🔥1
TypeScript. Интерфейсы
Интерфейс - надобъектная сущность, которая описывает, как должен выглядеть объект.
Это похоже на простое создание кастомного типа:
И используется интерфейс так же, как обычный тип:
Но интерфейс - более мощная концепция. Если
В интерфейсах также доступен модификатор
Если сразу не известно, сколько свойств должно быть в объекте, или неизвестны их имена, или они не важны для определяемого интерфейса, можно сделать так:
Интерфейсы могут описывать даже классы (похоже на абстрактный класс https://yangx.top/react_junior/401):
Чтобы реализовать этот интерфейс, заинтересованный класс использует ключевое слово
В классе при этом могут быть и дополнительные поля и методы, интерфейс лишь определяет минимальный набор полей.
Класс может реализовывать сразу несколько интерфейсов (перечисляются через запятую):
А сами интерфейсы могут наследовать от других интерфейсов:
#typescript
Интерфейс - надобъектная сущность, которая описывает, как должен выглядеть объект.
interface User {
name: string,
age?: number
}
Это похоже на простое создание кастомного типа:
type User = {
name: string,
age: number
}
И используется интерфейс так же, как обычный тип:
const john: User = {
name: 'John',
age: 30
}
Но интерфейс - более мощная концепция. Если
type
это просто создает псевдоним для типа, то интерфейс - это именованный тип объекта, который может наследоваться и расширяться другими интерфейсами.В интерфейсах также доступен модификатор
readonly
:interface User {
readonly name: string,
}
Если сразу не известно, сколько свойств должно быть в объекте, или неизвестны их имена, или они не важны для определяемого интерфейса, можно сделать так:
interface User {
name: string,
age: number,
[propName: string]: any
}
Интерфейсы могут описывать даже классы (похоже на абстрактный класс https://yangx.top/react_junior/401):
interface User {
name: string,
age: number,
getPass(): string
}
Чтобы реализовать этот интерфейс, заинтересованный класс использует ключевое слово
implements
:class Admin implements User {
name: string,
age: number,
nickName: string,
getPass() {
return `${this.name}${this.age}`;
}
}
В классе при этом могут быть и дополнительные поля и методы, интерфейс лишь определяет минимальный набор полей.
Класс может реализовывать сразу несколько интерфейсов (перечисляются через запятую):
interface User {
name: string,
age: number
}
interface Pass {
getPass(): string,
}
class Admin implements User, Pass {
name: string,
age: number,
getPass() {
return `${this.name}${this.age}`;
}
}
А сами интерфейсы могут наследовать от других интерфейсов:
interface Admin extends User {
getPass(): string,
}
#typescript
Telegram
React Junior
TypeScript. Абстрактные классы
В TypeScript есть возможность создавать абстрактные классы - концепция из сферы полиморфизма, обеспечивающая общий интерфейс для обычных классов, наследующих от абстрактного. При этом экземпляры абстрактного класса напрямую…
В TypeScript есть возможность создавать абстрактные классы - концепция из сферы полиморфизма, обеспечивающая общий интерфейс для обычных классов, наследующих от абстрактного. При этом экземпляры абстрактного класса напрямую…
👍1🔥1
TypeScript. Дженерики
Предположим, у нас есть функция, которая получает входной параметр и просто возвращает его. Причем параметр может быть любого типа:
const foo = function(data: any): any {
return data;
}
С точки зрения TS функция валидная, однако компилятор не может определить, с каким типом данных он работает, поэтому возможны ошибки, которые он не сможет поймать:
foo(10).length;
Чтобы вернуть контроль, нам нужно точнее указать тип. Как минимум, показать, что на выходе будет то же самое, что и на входе - один и тот же тип. Для этого в TS есть дженерики (обобщения).
Дженерик - это способ обозначить тип, не называя его напрямую. Обычно для обозначения типа используют букву T (type), но можно взять и другие буквы.
#typescript #дженерики
Предположим, у нас есть функция, которая получает входной параметр и просто возвращает его. Причем параметр может быть любого типа:
const foo = function(data: any): any {
return data;
}
С точки зрения TS функция валидная, однако компилятор не может определить, с каким типом данных он работает, поэтому возможны ошибки, которые он не сможет поймать:
foo(10).length;
Чтобы вернуть контроль, нам нужно точнее указать тип. Как минимум, показать, что на выходе будет то же самое, что и на входе - один и тот же тип. Для этого в TS есть дженерики (обобщения).
Дженерик - это способ обозначить тип, не называя его напрямую. Обычно для обозначения типа используют букву T (type), но можно взять и другие буквы.
#typescript #дженерики
👍1🔥1
Дженерики
То есть в угловых скобках мы указываем, что будем использовать какой-то тип T. Входной аргумент будет иметь этот тип T, и выходное значение тоже. Какой это конкретно тип, пока не известно, будет понятно уже при вызове функции.
Когда мы вызываем функцию с параметром 10, TypeScript берет тип этого параметра и считает, что T теперь равно этому типу. Теперь компилятор может определить, что у выходного значения нет свойства length, и выведет ошибку.
Или мы можем вручную указать тип при вызове функции (в угловых скобках перед списком параметров.
#typescript #дженерики
То есть в угловых скобках мы указываем, что будем использовать какой-то тип T. Входной аргумент будет иметь этот тип T, и выходное значение тоже. Какой это конкретно тип, пока не известно, будет понятно уже при вызове функции.
Когда мы вызываем функцию с параметром 10, TypeScript берет тип этого параметра и считает, что T теперь равно этому типу. Теперь компилятор может определить, что у выходного значения нет свойства length, и выведет ошибку.
Или мы можем вручную указать тип при вызове функции (в угловых скобках перед списком параметров.
#typescript #дженерики
👍2🔥1
TypeScript. Дженерики в классах
Дженерики можно использовать и в классах, нужные типы при этом указываются в угловых скобках сразу после имени класса. Типов может быть несколько, необязательно один.
При создании экземпляра конкретные типы (вместо заместителей) выведутся из входных параметров.
#typescript #дженерики
Дженерики можно использовать и в классах, нужные типы при этом указываются в угловых скобках сразу после имени класса. Типов может быть несколько, необязательно один.
При создании экземпляра конкретные типы (вместо заместителей) выведутся из входных параметров.
#typescript #дженерики
👍1🔥1
TypeScript. Декораторы
Паттерн Декоратор широко известен и активно применяется в программировании. Это способ добавить новую функциональность поверх существующей, не изменяя уже написанный код.
Грубо говоря, у нас есть некоторая функция, которая умеет что-то делать, например, складывает два числа:
Пишем простейший декоратор для этого:
Получается, что у нас тут есть основная функция
Декораторы в TS - это экспериментальная функция, поэтому для поддержки нужно добавить в tsconfig.json опцию
#typescript #tsдекораторы
Паттерн Декоратор широко известен и активно применяется в программировании. Это способ добавить новую функциональность поверх существующей, не изменяя уже написанный код.
Грубо говоря, у нас есть некоторая функция, которая умеет что-то делать, например, складывает два числа:
function add(a, b) {Мы хотим добавить для нее логирование - фиксацию каждого вызова с указанием его параметров.
return a + b;
}
Пишем простейший декоратор для этого:
function logger(fn) {Теперь завернем функцию в декоратор и получим декорированную функцию, которая делает то же самое, что и наша основная функция
return function(...params) {
console.log('Вызов функции', ...params); // регистрирует вызов
return fn(...params); // вызывает основную функцию
}
}
add
, но также имеет дополнительную функциональность - логирует свои вызовы.const addWithLogs = logger(add);В этот декоратор можно завернуть и любую другую функцию.
addWithLogs(4, 5); // 9
Получается, что у нас тут есть основная функция
add
, дополнительная функциональность (вызов console.log()
) и обертка над всем этим, которая принимает функцию, а затем вызывает ее, не забывая передать параметры. По сути вот так:function decorate(fn, decorator) {TypeScript предлагает удобную реализацию этого паттерна, инкапсулируя всю эту обертку. Правда работают они только с классами - можно декорировать сами классы, а также их свойства и методы, для обычных функций эта фича не поддерживается.
return function decoratedFn(...params) {
decorator(...params);
return fn(...params);
}
}
function logger(...params) {
console.log('Вызов функции', ...params);
}
function add(a, b) {
return a + b;
}
const addWithLogs = decorate(add, logger);
Декораторы в TS - это экспериментальная функция, поэтому для поддержки нужно добавить в tsconfig.json опцию
compilerOptions.experimentalDecorators
.#typescript #tsдекораторы
👍1🔥1
TypeScript. Декораторы классов
Самый простой вид декораторов в TS - декораторы классов. Они позволяют добавить новую функциональность целому классу.
Хороший пример есть в документации TS: декоратор
Декоратор класса - это простая функция с единственным аргументом
Обертка класса в декоратор осуществляется под капотом, а сам класс
#typescript #tsдекораторы
Самый простой вид декораторов в TS - декораторы классов. Они позволяют добавить новую функциональность целому классу.
Хороший пример есть в документации TS: декоратор
sealed
, который запрещает расширять прототип класса.Декоратор класса - это простая функция с единственным аргументом
constructor
- это собственно конструктор декорируемого класса. Через конструктор декоратор может повлиять на определение класса в целом:function sealed(constructor: Function) {Это мы описали "дополнительную функциональность". Чтобы применить ее к любому классу, нужно сделать вот так:
console.log('sealed decorator');
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealedПросто пишем
class User {
constructor(public name: string) {}
print(): void {
console.log(this.name);
}
}
@
плюс имя функции-декоратора над объявлением класса User
.Обертка класса в декоратор осуществляется под капотом, а сам класс
User
уже сразу имеет новую функциональность, добавленную декоратором. Например, мы не можем добавить в него новое свойство:Object.defineProperty(User, 'age', {В скомпилированном виде это все выглядит весьма громоздко
value: 17
});
// Cannot define property age, object is not extensible
#typescript #tsдекораторы
👍3🔥1
TypeScript. Декораторы методов класса
Декораторы методов выглядят уже немного сложнее, у них не один, а целых три параметра:
-
-
Дескриптор свойства - это объект, описывающий "настройки" свойства. У него есть поля:
-
-
-
Декораторы методов выглядят уже немного сложнее, у них не один, а целых три параметра:
function methodDecorator(-
target: any,
propertyName: string,
descriptor: PropertyDescriptor
) {
}
target
- это прототип класса. Для статического метода тут будет находиться функция-конструктор класса.-
propertyName
- это название метода.-
descriptor
- это дескриптор свойства (метода)Дескриптор свойства - это объект, описывающий "настройки" свойства. У него есть поля:
-
configurable
, -
enumerable
,-
value
- writable
- get
- set
Таким образом, в декораторе мы можем изменять настройки метода, изменяя его дескриптор. Например, можем сделать метод неизменяемым:function readable(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {Используется он так же, как и декоратор класса, только над методом:
descriptor.writable = false;
}
class User {Теперь для экземпляра класса
constructor(public name: string) {}
@readable
print(): void {
console.log(this.name);
}
}
User
не получится переопределить метод print
:const john = new User('John');#typescript #tsдекораторы
john.print = function() {
console.log('Method print has been changed');
}
john.print();
// Cannot assign to read only property 'print' of object 'User'
👍2🔥1
TypeScript. Декораторы параметров метода класса
Задекорировать можно даже параметры метода, хотя это уже идея посложнее.
Декоратор параметра принимает три аргумента:
-
-
-
Например, создадим декоратор, который будет логировать некоторые параметры метода.
На самом деле, сам декоратор параметра ничего логировать не будет, так как он не имеет доступа к вызовам метода. Но он может отметить параметры, которые нужно вывести в консоль.
Теперь напишем декоратор для самого метода. Он переопределит реализацию метода, через его дескриптор (поле
Задекорировать можно даже параметры метода, хотя это уже идея посложнее.
Декоратор параметра принимает три аргумента:
-
target
- прототип класса или конструктор (для статических методов)-
propertyKey
- название метода-
parameterIndex
- порядковый номер параметра Например, создадим декоратор, который будет логировать некоторые параметры метода.
На самом деле, сам декоратор параметра ничего логировать не будет, так как он не имеет доступа к вызовам метода. Но он может отметить параметры, которые нужно вывести в консоль.
function logParameter(Создаем уникальный ключ для метода и сохраняем массив параметров, которые нужно будет вывести в консоль при вызове.
target: any,
key: string,
index: number
) {
const metadataKey = `__log_${key}_parameters`;
const loggedParams = target[metadataKey];
if (Array.isArray(loggedParams)) {
loggedParams.push(index);
} else {
target[metadataKey] = [index];
}
}
Теперь напишем декоратор для самого метода. Он переопределит реализацию метода, через его дескриптор (поле
value
). При вызове метода мы сначала выведем те параметры, которые были декорированы, а затем уже вызовем сам оригинальный метод.function logMethod(#typescript #tsдекораторы
target: any,
key: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
const metadataKey = `__log_${key}_parameters`;
const loggedParams = target[metadataKey];
if (Array.isArray(loggedParams)) {
loggedParams.forEach(function(index) {
const arg = args[index];
console.log(`Метод: ${key}, параметр: ${index}`, arg);
})
}
const result = originalMethod.apply(this, args);
return result;
}
return descriptor;
}
👍4
TypeScript. Декораторы свойств
Функция-декоратор свойства принимает два параметра:
-
-
С помощью декоратора можно, например, изменить дескриптор свойства, переопределив его геттер и сеттер:
Функция-декоратор свойства принимает два параметра:
-
target
- прототип или конструктор (для статических свойств) класса-
propertyKey
- имя свойстваС помощью декоратора можно, например, изменить дескриптор свойства, переопределив его геттер и сеттер:
function formatProperty(target: any, propertyKey: string) {Применяется декоратор свойства точно так же, как уже рассмотренные декораторы классов и декораторы методов:
let _value = target[propertyKey];
const newGetter = function(): string {
return `Mr./Mrs. ${_value}`;
}
const newSetter = function(newValue: string): void {
_value = newValue;
}
delete target[propertyKey];
Object.defineProperty(target, propertyKey, {
get: newGetter,
set: newSetter
})
}
class User {#typescript #tsдекораторы
@formatProperty
name: string;
constructor(name: string) {
this.name = name;
}
print(): void {
console.log(this.name);
}
}
let john = new User('John');
john.print(); // Mr./Mrs. John
Telegram
React Junior
TypeScript. Декораторы классов
Самый простой вид декораторов в TS - декораторы классов. Они позволяют добавить новую функциональность целому классу.
Хороший пример есть в документации TS: декоратор sealed, который запрещает расширять прототип класса.…
Самый простой вид декораторов в TS - декораторы классов. Они позволяют добавить новую функциональность целому классу.
Хороший пример есть в документации TS: декоратор sealed, который запрещает расширять прототип класса.…
👍2
TypeScript. Декораторы методов доступа (геттеров и сеттеров)
И последнее, что мы можем задекорировать в TypeScript, - это методы доступа к свойствам класса (геттеры и сеттеры).
Принимает такой декоратор три параметра:
- target - прототип класса или функция-конструктор класса (для статических свойств).
- propertyName - название метода.
- descriptor - дескриптор свойства
Декоратор получает дескриптор метода, а значит, может влиять сразу и на геттер, и на сеттер, поэтому его достаточно указать только над одним из них.
Пример декоратора-валидатора:
И последнее, что мы можем задекорировать в TypeScript, - это методы доступа к свойствам класса (геттеры и сеттеры).
Принимает такой декоратор три параметра:
- target - прототип класса или функция-конструктор класса (для статических свойств).
- propertyName - название метода.
- descriptor - дескриптор свойства
Декоратор получает дескриптор метода, а значит, может влиять сразу и на геттер, и на сеттер, поэтому его достаточно указать только над одним из них.
Пример декоратора-валидатора:
function validator(Добавляем к сеттеру:
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalSet = descriptor.set;
descriptor.set = function(value: string) {
if (!value) {
throw new Error(`Invalid value for property ${propertyKey}`);
}
if (originalSet !== undefined) originalSet.call(this, value);
}
}
class User {#typescript #tsдекораторы
private _secret: string = "secret";
constructor(public name: string){
}
public get secret(): string {
return this._secret;
}
@validator
public set secret(n: string) {
this._secret = n;
}
}
let john = new User('John');
john.secret = ""; // Invalid value for property secret
👍1🔥1
TypeScript. Декораторы
В первом приближении с декораторами разобрались. Это простые функции, которые могут добавлять/изменять функциональность
- классов
- методов
- параметров методов
- свойств
- методов доступа к свойствам (геттеров/сеттеров)
В зависимости от типа декоратор получает разные параметры:
- конструктор класса или его прототип
- название свойства/метода
- дескриптор свойства метода
В основном декораторы изменяют свои аргументы, а не возвращают новое значение. Если все же возвращают новое (например, новый дескриптор свойства), то оно заменяет старое.
Мы все время указывали декоратор вот так:
В первом приближении с декораторами разобрались. Это простые функции, которые могут добавлять/изменять функциональность
- классов
- методов
- параметров методов
- свойств
- методов доступа к свойствам (геттеров/сеттеров)
В зависимости от типа декоратор получает разные параметры:
- конструктор класса или его прототип
- название свойства/метода
- дескриптор свойства метода
В основном декораторы изменяют свои аргументы, а не возвращают новое значение. Если все же возвращают новое (например, новый дескриптор свойства), то оно заменяет старое.
Мы все время указывали декоратор вот так:
@имя_функции_декоратораНо на самом деле, вместо имени функции тут может стоять выражение, результатом которого является функция. Например, можно устроить фабрику декораторов:
function decoratorsFactory(param) {#typescript #tsдекораторы
return function decorator(constructor: Function) {
//...
}
}
@decoratorsFactory('custom_value')
class User {
}
👍2🔥1
TypeScript. Утилиты (Readonly, Required, Partial)
TypeScript не просто дает возможность указыать типы для переменных и параметров и тем самым отслеживать ошибки. Он еще предлагает большой инструментарий для манипуляций с типами, превращения одних типов в другие с нужными характеристиками. Для этого у него есть множество утилит.
Сначала просто взглянем на эти утилиты, а разбираться в кейсах их использования будем уже позже.
Readonly
Делает все поля типа доступными только для чтения.
При попытке перезаписать их возникает ошибка.
Required
Делает все опциональные поля типа обязательными.
Если поле не указано в определении объекта, возникает ошибка.
Partial
Делает все обязательные поля типа опциональными.
Если поле не указано в определении объекта, ошибка не возникает.
Все эти утилиты работают с одним типом данных, не изменяют его и создают новый тип, который сопоставим с исходным (но имеет другие модификаторы свойств).
#typescript
TypeScript не просто дает возможность указыать типы для переменных и параметров и тем самым отслеживать ошибки. Он еще предлагает большой инструментарий для манипуляций с типами, превращения одних типов в другие с нужными характеристиками. Для этого у него есть множество утилит.
Сначала просто взглянем на эти утилиты, а разбираться в кейсах их использования будем уже позже.
Readonly
Делает все поля типа доступными только для чтения.
При попытке перезаписать их возникает ошибка.
Required
Делает все опциональные поля типа обязательными.
Если поле не указано в определении объекта, возникает ошибка.
Partial
Делает все обязательные поля типа опциональными.
Если поле не указано в определении объекта, ошибка не возникает.
Все эти утилиты работают с одним типом данных, не изменяют его и создают новый тип, который сопоставим с исходным (но имеет другие модификаторы свойств).
#typescript
👍1🔥1
TypeScript: объединения и пересечения
Объединения в TS - это аналог логического ИЛИ. Означает, что переменная должна быть одного из перечисленных типов.
Пересечения - это логическое И. Берет несколько типов и комбинирует их в один (типа
#typescript
Объединения в TS - это аналог логического ИЛИ. Означает, что переменная должна быть одного из перечисленных типов.
Пересечения - это логическое И. Берет несколько типов и комбинирует их в один (типа
Object.assign
).#typescript
👍1🔥1
TypeScript. Ограничения обобщенных типов
Еще немного об обобщенных типах, или дженериках.
Дженерик - это неопределенный тип, который на этапе объявления функции как бы "резервирует" место для настоящего типа, который будет определен только в момент вызова этой функции.
Когда мы указываем обобщенные типы (дженерики), то они буквально означают "любой тип".
1)
Например, в функции
Мы можем сузить перечень типов, которые ожидаем получить в параметре, что позволит компилятору свободнее работать с ними.
2)
Для этого добавим интерфейс
Ошибка пропала. Теперь компилятор сможет проверять входящие параметры.
3)
Если требуется обозначить только свойство
#typescript #дженерики
Еще немного об обобщенных типах, или дженериках.
Дженерик - это неопределенный тип, который на этапе объявления функции как бы "резервирует" место для настоящего типа, который будет определен только в момент вызова этой функции.
Когда мы указываем обобщенные типы (дженерики), то они буквально означают "любой тип".
1)
Например, в функции
getLength1
мы используем дженерик T
, который может быть абсолютно любым типом. Даже таким, в котором нет поля length
. Компилятор сразу же подчеркивает это.Мы можем сузить перечень типов, которые ожидаем получить в параметре, что позволит компилятору свободнее работать с ними.
2)
Для этого добавим интерфейс
Lengthwise
, который предусматривает наличие поля length
и расширим его нашим дженериком - функция getLength2
.Ошибка пропала. Теперь компилятор сможет проверять входящие параметры.
3)
Если требуется обозначить только свойство
length
, в TypeScript есть встроенный интерфейс ArrayLike
.#typescript #дженерики
👍2
Пример ограничения дженериков: обновление значений свойств одного объекта из другого.
Мы ожидаем на входе целевой объект
#typescript #дженерики
Мы ожидаем на входе целевой объект
target
(свойства которого нужно обновить) и объект-источник данных source
(из которого будут браться новые значения). Важно, чтобы у source
были те же поля, что и target
, ведь из них будут браться данные. По сути, тип source
расширяет тип target
. У него есть все поля target
, а также могут быть свои собственные.#typescript #дженерики
🔥2