TypeScript: Раскладываем tsconfig по полочкам
Разберемся в основных настройках TypeScript.
Статьи (рус.):
Часть 1
Часть 2
Исходные и конечные файлы
Работа с модулями
Использумая функциональность
Строгость
Линтинг
Компиляция
#typescript #подключение
Разберемся в основных настройках TypeScript.
Статьи (рус.):
Часть 1
Часть 2
Исходные и конечные файлы
files, include, exclude
- принимают массивы с именам файлов (или шаблонами имен).compilerOptions.allowJs
, compilerOptions.checkJS
- работа с JS-файлами (например, при миграции проекта с JS на TS).compilerOptions.outDir
, compilerOptions.outFile
- директория и имя файла для итоговой сборки.compilerOptions.resolveJsonModule
- можно импортировать JSON-файлы.jsx
- работа с JSX-разметкой (в React).Работа с модулями
compilerOptions.module
- система модулей, которую будет использовать скомпилированное приложение. По умолчанию commonjs
(exports, require), можно поставить 'es6' для фронтенд-проектов.compilerOptions.moduleResolution
- стратегия импорта модулей, в подавляющем большинстве случаев значение параметра равно node
.compilerOptions.esModuleInterop
- позволяет импортировать CommonJs-пакеты в стиле ES6.compilerOptions.forceConsistentCasingInFileNames
- режим чувствительности к регистру импортируемых файлов.Использумая функциональность
compilerOptions.target
- версия стандарта JS, в которую компилируется исходный код. По умолчанию (в сгенерированном файле) стоит es2016
, который поддерживается большинством браузеров.compilerOptions.compilerOptions.lib
- сторонняя функциональность, которая используется в проекте (полифиллы). По умолчанию для target: es6
подключаются методы стандарта ES6, а также DOM, DOM.Iterable, ScriptHost.Строгость
compilerOptions.strict
- включает строгий режим JS и ряд строгих проверок (на использование типа any
, неявного this
и т.д.). Можно заменить набором отдельных настроек.Линтинг
compilerOptions.noImplicitReturns
, compilerOptions.noUnusedParameters
, compilerOptions.allowUnreachableCode
, compilerOptions.removeComments
и тому подобное.Компиляция
compilerOptions.noEmitOnError
- не прерывать компиляцию при ошибке.#typescript #подключение
Хабр
TypeScript: Раскладываем tsconfig по полочкам. Часть 1
Я большой фанат TypeScript. Каждый свой новый проект я предпочитаю писать на нём, а не на чистом JavaScript. В данной статье я не буду рассматривать причины выбора TypeScript или о его преимуществах и...
👍1
TypeScript. Типы данных
Типы, знакомые из JavaScript:
- string
- number
- boolean
- null
- undefined
- object
Особые типы:
- void (для функций, которые ничего не возвращают)
- never (для функций, которые никогда не завершаются)
Еще есть массивы, кортежи, перечисления и функции (о них в следующих постах)
#typescript
Типы, знакомые из JavaScript:
- string
- number
- boolean
- null
- undefined
- object
Особые типы:
- void (для функций, которые ничего не возвращают)
- never (для функций, которые никогда не завершаются)
Еще есть массивы, кортежи, перечисления и функции (о них в следующих постах)
#typescript
👏2👍1
TypeScript. Массивоподобные типы
1. Массив, все элементы которого имеют одинаковый тип данных (массив чисел, массив строк)
Есть два способа определить массив:
- указываем тип данных, а после него квадратные скобки
- указываем конструктор Array, а после него в угловых скобках тип. Такая запись называется дженерик, вернемся к ним позже.
2. Массив с известным числом и порядком элементов разных типов (кортеж)
- в квадратных скобках перечисляются типы всех элементов по порядку
#typescript
1. Массив, все элементы которого имеют одинаковый тип данных (массив чисел, массив строк)
Есть два способа определить массив:
- указываем тип данных, а после него квадратные скобки
- указываем конструктор Array, а после него в угловых скобках тип. Такая запись называется дженерик, вернемся к ним позже.
2. Массив с известным числом и порядком элементов разных типов (кортеж)
- в квадратных скобках перечисляются типы всех элементов по порядку
#typescript
👍2🔥2
TypeScript. Перечисления (enums)
Видео (рус.): https://www.youtube.com/watch?v=FltLrtKWMak
Перечисление, или enum, - это способ создать коллекцию ключей, каждому из которых будет сопоставлено уникальное значение.
Под капотом у нас создается структура (среднее между массивом и объектом), содержащая четыре элемента. Каждому из них выдается порядковый номер.
Отличное решение для хранения наборов констант, к которым можно обращаться по имени.
Если дефолтный порядок нумерации не устраивает, можно установить любые кастомные индексы:
Можно, наоборот, получать элементы по индексу:
Можно вместо индексов использовать строковые значения:
В видео чуть поглубже показано подкапотное поведение
Но если добавить к объявлению перечисления слово
#typescript
Видео (рус.): https://www.youtube.com/watch?v=FltLrtKWMak
Перечисление, или enum, - это способ создать коллекцию ключей, каждому из которых будет сопоставлено уникальное значение.
enum Directions {
Up,
Down,
Left,
Right,
}
Под капотом у нас создается структура (среднее между массивом и объектом), содержащая четыре элемента. Каждому из них выдается порядковый номер.
Up
, Down
, Left
, Right
- это как бы названия свойств коллекции.
Directions.Up // 0
Directions.Down // 1
Отличное решение для хранения наборов констант, к которым можно обращаться по имени.
Если дефолтный порядок нумерации не устраивает, можно установить любые кастомные индексы:
enum Directions {
Up = 2,
Down = 4,
Left = 6,
Right = 8,
}
Можно, наоборот, получать элементы по индексу:
Directions[6] // 'Left'
Можно вместо индексов использовать строковые значения:
enum Links {
vk = 'https://vk.com/',
youtube = 'https://youtube.com'/,
facebook = 'https://facebook.com/'
}
В видео чуть поглубже показано подкапотное поведение
enum
. В частности, про то, что enum
компилируется в вызов функции (IIFO), создающий объект с коллекцией. То есть объект создается в любом случае, даже если не используется.Но если добавить к объявлению перечисления слово
const
, то объект не будет создан, если к нему нет ни одного обращения в дальнейшем.#typescript
👍3
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