1
1
---
2
- title : Mixins
2
+ title : mixin
3
3
layout : docs
4
4
permalink : /zh/docs/handbook/mixins.html
5
- oneline : Using the mixin pattern with TypeScript
5
+ oneline : 在 TypeScript 中使用 mixin
6
6
translatable : true
7
7
---
8
8
9
- Along with traditional OO hierarchies, another popular way of building up classes from reusable components is to build them by combining simpler partial classes.
10
- You may be familiar with the idea of mixins or traits for languages like Scala, and the pattern has also reached some popularity in the JavaScript community.
9
+ 除了传统的面向对象层次结构之外,另一种常用的构建类的方式是通过组合较简单的部分类来实现可重用组件。你可能熟悉类似 Scala 等语言中的 mixin 或 trait 的概念,这种模式在 JavaScript 社区中也相当流行。
11
10
12
- ## How Does A Mixin Work?
11
+ ## mixin 是如何工作的?
13
12
14
- The pattern relies on using generics with class inheritance to extend a base class.
15
- TypeScript's best mixin support is done via the class expression pattern.
16
- You can read more about how this pattern works in JavaScript [ here] ( https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/ ) .
13
+ 该模式依赖于使用类继承的泛型来扩展基类。TypeScript 最好的 mixin 支持是通过类表达式模式实现的。你可以在[ 这里] ( https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/ ) 阅读更多关于此模式在 JavaScript 中的工作方式。
17
14
18
- To get started, we'll need a class which will have the mixins applied on top of:
15
+ 作为起点,我们编写一个应用 mixin 的类:
19
16
20
17
``` ts twoslash
21
18
class Sprite {
@@ -29,22 +26,22 @@ class Sprite {
29
26
}
30
27
```
31
28
32
- Then you need a type and a factory function which returns a class expression extending the base class.
29
+ 然后,你需要一个类型和一个工厂函数,该函数返回一个扩展基类的类表达式。
33
30
34
31
``` ts twoslash
35
- // To get started, we need a type which we'll use to extend
36
- // other classes from. The main responsibility is to declare
37
- // that the type being passed in is a class.
32
+ // 要开始,我们需要一个类型,我们将使用它来扩展
33
+ // 其他类。其主要职责是声明
34
+ // 传入的类型是一个类。
38
35
39
36
type Constructor = new (... args : any []) => {};
40
37
41
- // This mixin adds a scale property, with getters and setters
42
- // for changing it with an encapsulated private property:
38
+ // 此 mixin 添加一个 scale 属性,该属性具有用于更改它的 getter 和 setter
39
+ // 以及一个封装的私有属性:
43
40
44
41
function Scale<TBase extends Constructor >(Base : TBase ) {
45
42
return class Scaling extends Base {
46
- // Mixins may not declare private/protected properties
47
- // however, you can use ES2020 private fields
43
+ // mixin 可能不会声明私有/受保护属性
44
+ // 但你可以使用 ES2020 私有字段
48
45
_scale = 1 ;
49
46
50
47
setScale(scale : number ) {
@@ -58,9 +55,9 @@ function Scale<TBase extends Constructor>(Base: TBase) {
58
55
}
59
56
```
60
57
61
- With these all set up, then you can create a class which represents the base class with mixins applied:
58
+ 设置好这些之后,你可以创建一个表示已应用 mixin 的基类的类:
62
59
63
- ``` ts twoslash
60
+ ``` ts
64
61
class Sprite {
65
62
name = " " ;
66
63
x = 0 ;
@@ -73,8 +70,8 @@ class Sprite {
73
70
type Constructor = new (... args : any []) => {};
74
71
function Scale<TBase extends Constructor >(Base : TBase ) {
75
72
return class Scaling extends Base {
76
- // Mixins may not declare private/protected properties
77
- // however, you can use ES2020 private fields
73
+ // 混合类可能不能声明私有/受保护属性
74
+ // 但是,你可以使用 ES2020 私有字段
78
75
_scale = 1 ;
79
76
80
77
setScale(scale : number ) {
@@ -87,30 +84,29 @@ function Scale<TBase extends Constructor>(Base: TBase) {
87
84
};
88
85
}
89
86
// ---cut---
90
- // Compose a new class from the Sprite class,
91
- // with the Mixin Scale applier:
87
+ // 从 Sprite 类组合一个新类,
88
+ // 使用 Mixin Scale:
92
89
const EightBitSprite = Scale (Sprite );
93
90
94
91
const flappySprite = new EightBitSprite (" Bird" );
95
92
flappySprite .setScale (0.8 );
96
93
console .log (flappySprite .scale );
97
94
```
98
95
99
- ## Constrained Mixins
96
+ ## 有限制的 Mixin
100
97
101
- In the above form, the mixin's have no underlying knowledge of the class which can make it hard to create the design you want.
98
+ 在上面的形式中, mixin 没有关于类的基础知识,这可能会使得创建你想要的设计变得困难。
102
99
103
- To model this, we modify the original constructor type to accept a generic argument.
100
+ 为了模拟这一点,我们修改原始构造函数类型以接受一个泛型参数。
104
101
105
102
``` ts twoslash
106
- // This was our previous constructor:
103
+ // 这是我们先前的构造函数:
107
104
type Constructor = new (... args : any []) => {};
108
- // Now we use a generic version which can apply a constraint on
109
- // the class which this mixin is applied to
105
+ // 现在我们使用一个泛型版本,它可以对应用此 mixin 的类施加约束
110
106
type GConstructor <T = {}> = new (... args : any []) => T ;
111
107
```
112
108
113
- This allows for creating classes which only work with constrained base classes:
109
+ 这样可以创建仅适用于有约束基类的类:
114
110
115
111
``` ts twoslash
116
112
type GConstructor <T = {}> = new (... args : any []) => T ;
@@ -129,7 +125,7 @@ type Spritable = GConstructor<Sprite>;
129
125
type Loggable = GConstructor <{ print: () => void }>;
130
126
```
131
127
132
- Then you can create mixins which only work when you have a particular base to build on:
128
+ 然后,你可以创建仅在有特定基类时才起作用的 mixins:
133
129
134
130
``` ts twoslash
135
131
type GConstructor <T = {}> = new (... args : any []) => T ;
@@ -150,22 +146,20 @@ type Loggable = GConstructor<{ print: () => void }>;
150
146
function Jumpable<TBase extends Positionable >(Base : TBase ) {
151
147
return class Jumpable extends Base {
152
148
jump() {
153
- // This mixin will only work if it is passed a base
154
- // class which has setPos defined because of the
155
- // Positionable constraint.
149
+ // 只有在传递了具有 setPos 定义的基类时,这个 mixin 才能起作用,这是由于 Positionable 的约束。
156
150
this .setPos (0 , 20 );
157
151
}
158
152
};
159
153
}
160
154
```
161
155
162
- ## Alternative Pattern
156
+ ## 替代模式
163
157
164
- Previous versions of this document recommended a way to write mixins where you created both the runtime and type hierarchies separately, then merged them at the end:
158
+ 本文档的先前版本推荐一种编写 mixins 的方式,其中你分别创建运行时层次结构和类型层次结构,然后在最后将它们合并:
165
159
166
160
``` ts twoslash
167
161
// @strict: false
168
- // Each mixin is a traditional ES class
162
+ // 每个 mixin 都是一个传统的 ES 类
169
163
class Jumpable {
170
164
jump() {}
171
165
}
@@ -174,24 +168,22 @@ class Duckable {
174
168
duck() {}
175
169
}
176
170
177
- // Including the base
171
+ // 包括基类
178
172
class Sprite {
179
173
x = 0 ;
180
174
y = 0 ;
181
175
}
182
176
183
- // Then you create an interface which merges
184
- // the expected mixins with the same name as your base
177
+ // 然后你创建一个接口,将期望的 mixins 与与基类同名的接口合并
185
178
interface Sprite extends Jumpable , Duckable {}
186
- // Apply the mixins into the base class via
187
- // the JS at runtime
179
+ // 通过运行时的 JS 将 mixins 应用到基类
188
180
applyMixins (Sprite , [Jumpable , Duckable ]);
189
181
190
182
let player = new Sprite ();
191
183
player .jump ();
192
184
console .log (player .x , player .y );
193
185
194
- // This can live anywhere in your codebase:
186
+ // 这段代码可以放在代码库中的任何位置:
195
187
function applyMixins(derivedCtor : any , constructors : any []) {
196
188
constructors .forEach ((baseCtor ) => {
197
189
Object .getOwnPropertyNames (baseCtor .prototype ).forEach ((name ) => {
@@ -206,21 +198,20 @@ function applyMixins(derivedCtor: any, constructors: any[]) {
206
198
}
207
199
```
208
200
209
- This pattern relies less on the compiler, and more on your codebase to ensure both runtime and type-system are correctly kept in sync.
201
+ 这种模式更少地依赖于编译器,更多地依赖于你的代码库来确保运行时和类型系统正确地保持同步。
210
202
211
- ## Constraints
203
+ ## 约束
212
204
213
- The mixin pattern is supported natively inside the TypeScript compiler by code flow analysis.
214
- There are a few cases where you can hit the edges of the native support.
205
+ 在 TypeScript 编译器内部,通过代码流分析本地支持 mixin 模式。有一些情况会使你触及本地支持的边缘。
215
206
216
- #### Decorators and Mixins [ ` #4881 ` ] ( https://github.com/microsoft/TypeScript/issues/4881 )
207
+ #### 装饰器和 Mixins [ ` #4881 ` ] ( https://github.com/microsoft/TypeScript/issues/4881 )
217
208
218
- You cannot use decorators to provide mixins via code flow analysis:
209
+ 你不能使用装饰器通过代码流分析提供 mixins:
219
210
220
211
``` ts twoslash
221
212
// @experimentalDecorators
222
213
// @errors: 2339
223
- // A decorator function which replicates the mixin pattern:
214
+ // 一个复制 mixin 模式的装饰器函数:
224
215
const Pausable = (target : typeof Player ) => {
225
216
return class Pausable extends target {
226
217
shouldFreeze = false ;
@@ -233,24 +224,23 @@ class Player {
233
224
y = 0 ;
234
225
}
235
226
236
- // The Player class does not have the decorator's type merged:
227
+ // Player 类没有合并装饰器的类型:
237
228
const player = new Player ();
238
229
player .shouldFreeze ;
239
230
240
- // The runtime aspect could be manually replicated via
241
- // type composition or interface merging.
231
+ // 可以通过手动复制运行时方面来复制
232
+ // 类型组合或接口合并。
242
233
type FreezablePlayer = Player & { shouldFreeze: boolean };
243
234
244
235
const playerTwo = (new Player () as unknown ) as FreezablePlayer ;
245
236
playerTwo .shouldFreeze ;
246
237
```
247
238
248
- #### Static Property Mixins [ ` #17829 ` ] ( https://github.com/microsoft/TypeScript/issues/17829 )
239
+ #### 静态属性 Mixins [ ` #17829 ` ] ( https://github.com/microsoft/TypeScript/issues/17829 )
249
240
250
- More of a gotcha than a constraint.
251
- The class expression pattern creates singletons, so they can't be mapped at the type system to support different variable types.
241
+ 更多是一个要注意的地方,而不是一个约束。类表达式模式创建单例,因此无法在类型系统中映射它们以支持不同的变量类型。
252
242
253
- You can work around this by using functions to return your classes which differ based on a generic:
243
+ 你可以通过使用函数返回基于泛型不同的类来解决这个问题:
254
244
255
245
``` ts twoslash
256
246
function base<T >() {
0 commit comments