Skip to content

Commit 36be18e

Browse files
committed
feat: decorators usage
1 parent 4364958 commit 36be18e

File tree

2 files changed

+189
-68
lines changed

2 files changed

+189
-68
lines changed

CHANGELOG.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# 1.0.0 (2020-10-14)
1+
# 1.0.0 (2020-10-15)
22

33

44
### Bug Fixes
@@ -30,9 +30,10 @@
3030
* advanced types nullable; update union, assertion; others chores ([1b5936a](https://github.com/Rain120/typescript-guide/commit/1b5936aac1fe2c6363c90083231f66779b654a1e))
3131
* build in objects ([b62cd07](https://github.com/Rain120/typescript-guide/commit/b62cd07384f6423400d485bc3c4b68c6649c0ec2))
3232
* class ([78ff3cc](https://github.com/Rain120/typescript-guide/commit/78ff3ccf5e321f198777deb8fd20dc487add0bc0))
33+
* decorators; plugin with math latex ([4364958](https://github.com/Rain120/typescript-guide/commit/4364958b84092d08a312ea839e730de008d1847e))
3334
* function ([5dba78c](https://github.com/Rain120/typescript-guide/commit/5dba78cd2eb6d18c70c4524ae328f4514c5eb1dd))
34-
* github action deploy workflows ([a98f275](https://github.com/Rain120/typescript-guide/commit/a98f27562f0cf7e3a82b46fa95fba8c1f2cd678b))
3535
* github action deploy workflows ([ae5128e](https://github.com/Rain120/typescript-guide/commit/ae5128e2dd7521698a0b5f11f783f48d41022e12))
36+
* github action deploy workflows ([a98f275](https://github.com/Rain120/typescript-guide/commit/a98f27562f0cf7e3a82b46fa95fba8c1f2cd678b))
3637
* infer ([ddb4ae9](https://github.com/Rain120/typescript-guide/commit/ddb4ae96a8e669e266f7d76533e6f6c5660d3286))
3738
* init typscript guide & add guide, introduction, base ([365b637](https://github.com/Rain120/typescript-guide/commit/365b637d872cc92c23a04c09788d50001ee46a73))
3839
* intersection & union types; utility version; typescripts reference ([06fc3de](https://github.com/Rain120/typescript-guide/commit/06fc3de9cd11890024e172ee69b480924ddad295))
@@ -41,9 +42,9 @@
4142
* plop auto create docs model ([1f5a2f9](https://github.com/Rain120/typescript-guide/commit/1f5a2f94bbd7a430bbfbb48a09718b8ec9d14190))
4243
* plop new docs & update alias; update plop template; add docs catalog & folders ([dd5326a](https://github.com/Rain120/typescript-guide/commit/dd5326ac2934069c2cb10238c674e4dc86844274))
4344
* refactor types(intersection, union, guard) to advanced types ([bde41ab](https://github.com/Rain120/typescript-guide/commit/bde41ab8e61ae59f21c907c7a1a86e932ee71f31))
45+
* **heading:** 加入特殊 heading 的处理; ignore IDE 相关的文件 ([5e9070b](https://github.com/Rain120/typescript-guide/commit/5e9070baf3b36cc0e753b9bde3a8aaec58590314))
4446
* ts basic type; update logo; guide; add editorconfig ([c0b6eb2](https://github.com/Rain120/typescript-guide/commit/c0b6eb272ab4d87706902cdda365230e507b860b))
4547
* ts operator; compile config; fix: playground frame width bug ([f2bcaa0](https://github.com/Rain120/typescript-guide/commit/f2bcaa05bfdf574037ec54ed3e651ce1d1353b5c))
46-
* **heading:** 加入特殊 heading 的处理; ignore IDE 相关的文件 ([5e9070b](https://github.com/Rain120/typescript-guide/commit/5e9070baf3b36cc0e753b9bde3a8aaec58590314))
4748
* type assertion ([f77f51c](https://github.com/Rain120/typescript-guide/commit/f77f51c574f036d6079742eca8f8affa7b06f617))
4849
* update the okrs about guide ([a762e9c](https://github.com/Rain120/typescript-guide/commit/a762e9cb156ac0bcdbdc64f0b477e41c49fb9e8d))
4950
* utility types; alias set bottom title; update generics params; ([a306a25](https://github.com/Rain120/typescript-guide/commit/a306a25c512246ef230a445ccb4e292eef8b8a7d))

docs/zh/decorators/README.md

Lines changed: 185 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
1-
## 定义 <Badge text='WIP' type='warning' />
1+
## 定义
22

3-
**装饰器**是一种特殊类型的声明它能够被附加到[类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators)[方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators) [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators)[属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。 装饰器使用 `@expression`这种形式`expression`求值后必须为一个函数它会在运行时被调用被装饰的声明信息做为参数传入。
3+
**装饰器**是一种特殊类型的声明, 它能够被附加到[类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators), [方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators), [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators), [属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。 装饰器使用 `@expression` 这种形式, `expression` 求值后必须为一个函数, 它会在运行时被调用, 被装饰的声明信息做为参数传入。
44

55
了解更多有关装饰器实现原理的知识 👉👉👉 [Javascript Decorator (装饰器) 实现原理及其使用](https://rain120.github.io/study-notes/#/notes/javascript/key-concept/decorator?id=javascript-decorator-装饰器-实现原理及其使用)
66

77
### 类型 & 优先级
88

99
**优先级依次往下执行**
1010

11-
1. 参数装饰器 `(Parameter Decorators)`
11+
1. 参数装饰器 `(Parameter Decorators)`
1212

13-
**参数装饰器**声明在一个参数声明之前紧靠着参数声明。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件.d.ts),重载或其它外部上下文比如 `declare`的类里。
13+
**参数装饰器**声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件`(.d.ts)`, 重载或其它外部上下文(比如 `declare`的类)里。
1414

1515
2. 方法装饰器 `(Method Decorators)`
1616

17-
**方法装饰器**声明在一个方法的声明之前紧靠着方法声明。 它会被应用到方法的 *属性描述符*可以用来监视修改或者替换方法定义。 方法装饰器不能用在声明文件( `.d.ts`),重载或者任何外部上下文比如`declare`的类中。
17+
**方法装饰器**声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的 *属性描述符*, 可以用来监视, 修改或者替换方法定义。 方法装饰器不能用在声明文件`(.d.ts)`, 重载或者任何外部上下文(比如`declare`的类)中。
1818

1919
3. 访问器或属性装饰器 `(Accessor or Property Decorators)`
2020

21-
**属性装饰器**声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中(.d.ts),或者任何外部上下文比如 `declare`的类)里。
21+
**访问器装饰器**声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 *属性描述符*并且可以用来监视, 修改或替换一个访问器的定义。 访问器装饰器不能用在声明文件中`(.d.ts)`, 或者任何外部上下文(比如 `declare` 的类)里。
2222

23-
1. 类属性
24-
2. 构造函数参数列表 `(使用类构造函数装饰器时)`
23+
**属性装饰器**声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中`(.d.ts)`, 或者任何外部上下文(比如 `declare` 的类)里。
2524

26-
**Note:** 访问器 `get` `set`
25+
1. 类属性
26+
2. 构造函数参数列表 `(使用类构造函数装饰器时)`
27+
28+
**Note:** 访问器 `get` `set`
2729

2830
4. 类装饰器 `(Class Decorators)`
2931

30-
**类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数可以**用来监视修改或替换类定义**。 类装饰器不能用在声明文件中( `.d.ts`)也不能用在任何外部上下文中(比如`declare`的类)。
32+
**类装饰器** 在类声明之前被声明 (紧靠着类声明)。 类装饰器应用于类构造函数, 可以**用来监视, 修改或替换类定义**。 类装饰器不能用在声明文件中( `.d.ts`), 也不能用在任何外部上下文中(比如`declare`的类)。
3133

3234
## 使用
3335

34-
若要启用实验性的装饰器特性你必须在命令行或`tsconfig.json`里启用`experimentalDecorators`编译器选项
36+
若要启用实验性的装饰器特性, 你必须在命令行或`tsconfig.json`里启用`experimentalDecorators`编译器选项:
3537

3638
**命令行**:
3739

@@ -52,7 +54,7 @@ tsc --target ES5 --experimentalDecorators
5254

5355
### 装饰器组合
5456

55-
多个装饰器可以同时应用声明到一个 [类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators)[方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators) [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators)[属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。**Eg:**
57+
多个装饰器可以同时应用声明到一个 [类声明](http://www.tslang.cn/docs/handbook/decorators.html#class-decorators), [方法](http://www.tslang.cn/docs/handbook/decorators.html#method-decorators), [访问符](http://www.tslang.cn/docs/handbook/decorators.html#accessor-decorators), [属性](http://www.tslang.cn/docs/handbook/decorators.html#property-decorators)[参数](http://www.tslang.cn/docs/handbook/decorators.html#parameter-decorators)上。
5658

5759
```ts
5860
// 一行写法
@@ -64,32 +66,32 @@ tsc --target ES5 --experimentalDecorators
6466
isHandsome() {}
6567
```
6668

67-
当复合 **f****g**[复合](https://zh.wikipedia.org/wiki/%E5%A4%8D%E5%90%88%E5%87%BD%E6%95%B0) `(把一个函数的输出作为另一个函数的输入)`的结果 $(f ∘ g)(x) = f(g(x))$。
69+
当复合 **f****g**, [复合](https://zh.wikipedia.org/wiki/%E5%A4%8D%E5%90%88%E5%87%BD%E6%95%B0) `(把一个函数的输出作为另一个函数的输入)`的结果 $(f ∘ g)(x) = f(g(x))$。
6870

6971
**Note:** 当在一个地方使用**多个装饰器**
7072

71-
- **由上至下**依次对装饰器表达式求值
72-
- 执行顺序是 **从下往上** 依次执行。
73+
- **由上至下**依次对装饰器表达式求值
74+
- 执行顺序是 **从下往上** 依次执行。
7375

7476
```ts
7577
function first() {
76-
console.log('first: evaluated');
77-
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
78-
console.log('first: called')
79-
}
78+
console.log('first: evaluated');
79+
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
80+
console.log('first: called');
81+
};
8082
}
8183

8284
function second() {
83-
console.log('second: evaluated');
84-
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
85-
console.log('second: called')
86-
}
85+
console.log('second: evaluated');
86+
return (target, propertyKey: string, descriptor: PropertyDescriptor) => {
87+
console.log('second: called');
88+
};
8789
}
8890

8991
class Example {
90-
@second
91-
@first
92-
method() {}
92+
@second
93+
@first
94+
method() {}
9395
}
9496

9597
// 'second: evaluated'
@@ -100,81 +102,199 @@ class Example {
100102

101103
### 参数装饰器
102104

105+
参数装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
106+
107+
1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
108+
2. 成员的名字。
109+
3. 参数在函数参数列表中的索引。
110+
111+
::: warning
112+
注意: 参数装饰器只能用来监视一个方法的参数是否被传入。
113+
:::
114+
115+
参数装饰器的返回值会被忽略。
116+
103117
```ts
118+
function parameterDecorator(value: boolean) {
119+
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
120+
console.log('parameterDecorator');
121+
};
122+
}
104123

105-
```
124+
class Boy {
125+
name: string;
126+
age: number;
127+
handsome: boolean;
106128

129+
constructor(name, handsome) {
130+
this.name = name;
131+
this.handsome = handsome;
132+
}
107133

134+
setAge(@parameterDecorator('parameterDecorator') age: number) {
135+
this.age = age;
136+
}
137+
}
138+
```
108139

109140
### 方法装饰器
110141

142+
方法装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
143+
144+
1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
145+
2. 成员的名字。
146+
3. 成员的 **属性描述符**
147+
148+
::: warning
149+
如果代码输出目标版本小于`ES5`, *属性描述符*将会是`undefined`
150+
:::
151+
152+
如果方法装饰器返回一个值, 它会被用作方法的*属性描述符*
153+
154+
::: warning
155+
如果代码输出目标版本小于`ES5`返回值会被忽略。
156+
:::
157+
111158
```ts
159+
function methodDecorator(value: boolean) {
160+
return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
161+
target[propertyKey] = value;
162+
};
163+
}
112164

113-
```
165+
class Boy {
166+
name: string;
167+
handsome: boolean;
114168

169+
@propertyDecorator('属性装饰器', Boy)
170+
public age: number = 18;
115171

172+
constructor(name, handsome) {
173+
this.name = name;
174+
this.handsome = handsome;
175+
}
176+
177+
@methodDecorator(true)
178+
isHandsome() {
179+
return this.handsome;
180+
}
181+
}
182+
```
116183

117184
### 访问器或属性装饰器
118185

119186
#### 属性装饰器
120187

188+
属性装饰器表达式会在运行时当作函数被调用, 传入下列 `2` 个参数:
189+
190+
1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
191+
2. 成员的名字。
192+
193+
::: warning
194+
**属性描述符** 不会做为参数传入属性装饰器, 这与`TypeScript`是如何初始化属性装饰器的有关。 因为目前没有办法在定义一个原型对象的成员时描述一个实例属性, 并且没办法监视或修改一个属性的初始化方法。返回值也会被忽略。因此, 属性描述符只能用来监视类中是否声明了某个名字的属性。
195+
:::
196+
121197
```ts
122198
function propertyDecorator(value: string, theClass) {
123-
console.log(value)
124-
return function(prototype, key){
125-
console.log('AccessDecorator')
126-
}
199+
console.log(value);
200+
return function(prototype, key) {
201+
console.log('AccessDecorator');
202+
};
127203
}
128204

129205
class Boy {
130-
name: string;
131-
handsome: boolean;
132-
133-
@propertyDecorator('属性装饰器', Boy)
134-
public age: number = 18;
135-
136-
constructor(name, handsome) {
137-
this.name = name;
138-
this.handsome = handsome;
139-
}
140-
141-
@AccessDecorator('访问器装饰器')
142-
get isHandsome() {
143-
return this.handsome;
144-
}
206+
name: string;
207+
handsome: boolean;
208+
209+
@propertyDecorator('属性装饰器', Boy)
210+
public age: number = 18;
211+
212+
constructor(name, handsome) {
213+
this.name = name;
214+
this.handsome = handsome;
215+
}
216+
217+
@AccessDecorator('访问器装饰器')
218+
get isHandsome() {
219+
return this.handsome;
220+
}
145221
}
146222
```
147223

224+
#### 访问器装饰器
225+
226+
::: warning
227+
`TypeScript`不允许同时装饰一个成员的`get``set` 访问器。取而代之的是, 一个成员的所有装饰的必须应用在文档顺序的第一个访问器上。这是因为, 在装饰器应用于一个**属性描述符**时, 它联合了 `get``set` 访问器, 而不是分开声明的。
228+
:::
148229

230+
访问器装饰器表达式会在运行时当作函数被调用, 传入下列 3 个参数:
149231

150-
#### 访问器装饰器
232+
1. 对于静态成员来说是类的构造函数, 对于实例成员是类的原型对象。
233+
2. 成员的名字。
234+
3. 成员的**属性描述符**
235+
236+
::: warning
237+
如果代码输出目标版本小于 `ES5`, **Property Descriptor** 将会是 `undefined`
238+
:::
239+
240+
如果访问器装饰器返回一个值, 它会被用作方法的*属性描述符*
241+
242+
::: warning
243+
如果代码输出目标版本小于 `ES5` 返回值会被忽略。
244+
:::
151245

152246
```ts
153247
function AccessDecorator(value: string) {
154-
console.log(value)
155-
return function(){
156-
console.log('AccessDecorator')
157-
}
248+
console.log(value);
249+
return function() {
250+
console.log('AccessDecorator');
251+
};
158252
}
159253

160254
class Boy {
161-
name: string;
162-
handsome: boolean;
163-
164-
constructor(name, handsome) {
165-
this.name = name;
166-
this.handsome = handsome;
167-
}
168-
169-
@AccessDecorator('访问器装饰器')
170-
get isHandsome() {
171-
return this.handsome;
172-
}
255+
name: string;
256+
handsome: boolean;
257+
258+
constructor(name, handsome) {
259+
this.name = name;
260+
this.handsome = handsome;
261+
}
262+
263+
@AccessDecorator('访问器装饰器')
264+
get isHandsome() {
265+
return this.handsome;
266+
}
173267
}
174268
```
175269

176270
### 类装饰器
177271

272+
类装饰器表达式会在运行时当作函数被调用, **类的构造函数作为其唯一的参数**
273+
274+
如果类装饰器返回一个值, 它会使用提供的构造函数来替换类的声明。
275+
276+
::: warning
277+
如果你要返回一个新的构造函数, 你必须注意处理好原来的原型链。在运行时的装饰器调用逻辑中 **不会** 为你做这些。
278+
:::
279+
280+
```ts
281+
function sealed(constructor: Function) {
282+
Object.seal(constructor);
283+
Object.seal(constructor.prototype);
284+
}
285+
286+
@sealed
287+
class Greeter {
288+
greeting: string;
289+
constructor(message: string) {
290+
this.greeting = message;
291+
}
292+
greet() {
293+
return 'Hello, ' + this.greeting;
294+
}
295+
}
296+
```
297+
178298
## 快来耍耍啊
179299

180300
### 🌰🌰
@@ -203,4 +323,4 @@ class Boy {
203323

204324
[handbook - decorators](https://www.typescriptlang.org/docs/handbook/decorators.html)
205325

206-
[使用 TypeScript 装饰器装饰你的代码](https://codeburst.io/decorate-your-code-with-typescript-decorators-5be4a4ffecb4)
326+
[使用 TypeScript 装饰器装饰你的代码](https://codeburst.io/decorate-your-code-with-typescript-decorators-5be4a4ffecb4)

0 commit comments

Comments
 (0)