classes 类类型
# 目录
- 目录
- Class Members 类成员
- readonly
- Constructors 构造器
- Super Calls 父级构造器调用
- Methods 方法
- Getters / Setters
- Index Signatures 索引签名
- Class Heritage 类继承
- Member Visibility 会员能见度
- Static Members 固定成员
- Special Static Names 特殊静态名称
- Why No Static Classes? 为什么没有静态类?
- static Blocks in Classes 类中的块
- Generic Classes 通用类
- Type Parameters in Static Members 静态成员中的类型参数
- this at Runtime in Classes在运行时在类中
- Arrow Functions 箭头函数
- this parameters 参数
- this Types 类类型
- this-based type guards 基于类型的保护
- Parameter Properties 参数属性
- Class Expressions 类别表达式
- abstract Classes and Members 班级及成员
- Abstract Construct Signatures 抽象构造签名
- Relationships Between Classes 阶级之间的关系
# Class Members 类成员
# --strictPropertyInitialization
The strictPropertyInitialization setting controls whether class fields need to be initialized in the constructor. strictPropertyInitialization 设置控制是否需要在构造函数中初始化类字段。
If you intend to definitely initialize a field through means other than the constructor (for example, maybe an external library is filling in part of your class for you), you can use the definite assignment assertion operator, !: 如果您打算通过构造函数以外的方法 (例如,可能有一个外部库为您填充了类的一部分) 确切地初始化字段,那么您可以使用确定的赋值断言运算符,!
# readonly
Fields may be prefixed with the readonly modifier. This prevents assignments to the field outside of the constructor. 字段可以用 readonly 修饰符作为前缀。这样可以防止赋值到构造函数之外的字段。
# Constructors 构造器
Class constructors are very similar to functions. You can add parameters with type annotations, default values, and overloads. 类构造函数与函数非常相似。你可以添加带有类型注释、默认值和重载的参数。
There are just a few differences between class constructor signatures and function signatures: 类构造函数签名和函数签名只有一些区别:
- Constructors can’t have type parameters - these belong on the outer class declaration. 构造函数不能有类型参数 —— 它们属于外部类声明。
- onstructors can’t have return type annotations - the class instance type is always what’s returned 构造函数不能有返回类型注释 —— 返回的总是类实例类型。
# Super Calls 父级构造器调用
# Methods 方法
# Getters / Setters
TypeScript has some special inference rules for accessors: 对访问器有一些特殊的推理规则:
- If get exists but no set, the property is automatically readonly. 如果 get 存在但没有设置,则属性自动为只读
- If the type of the setter parameter is not specified, it is inferred from the return type of the getter. 如果没有指定 setter 参数的类型,则从 getter 的返回类型推断出来
- Getters and setters must have the same Member Visibility. Getters 和 setter 必须具有相同的成员 Visibility
# Index Signatures 索引签名
class MyClass {
[s: string]: boolean | ((s: string) => boolean);
check(s: string) {
return this[s] as boolean;
}
}
2
3
4
5
6
7
# Class Heritage 类继承
- implements: Classes may also implement multiple interfaces, e.g. class C implements A, B {}.
- extends:A derived class has all the properties and methods of its base class, and also define additional members. 派生类具有其基类的所有属性和方法,并定义其他成员。
- Overriding Methods 覆盖方法:A derived class can also override a base class field or property. You can use the super. syntax to access base class methods. 派生类还可以重写基类字段或属性。你可以使用管理员。语法来访问基类方法。
- Initialization Order 初始化顺序
- Inheriting Built-in Types 继承内置类型
In ES2015, constructors which return an object implicitly substitute the value of this for any callers of super(...). It is necessary for generated constructor code to capture any potential return value of super(...) and replace it with this. 在 es2015 中,返回对象的构造函数隐式地用这个值替换任何 super (...) 调用方。生成的构造函数代码必须捕获 super (...) 的任何潜在返回值,并将其替换为这个值。
As a result, subclassing Error, Array, and others may no longer work as expected. This is due to the fact that constructor functions for Error, Array, and the like use ECMAScript 6’s new.target to adjust the prototype chain; however, there is no way to ensure a value for new.target when invoking a constructor in ECMAScript 5. Other downlevel compilers generally have the same limitation by default. 因此,子类化 Error、 Array 和其他元素可能无法正常工作。这是因为 Error,Array 和类似的构造函数使用 ECMAScript 6 的 new.target 来调整原型链;然而,当调用 ECMAScript 5 中的构造函数时,无法确保 new.target 的值。默认情况下,其他底层编译器通常具有相同的限制。
As a recommendation, you can manually adjust the prototype immediately after any super(...) calls. 作为建议,您可以在任何 super (...) 调用之后立即手动调整原型。
class MsgError extends Error {
constructor(m: string) {
super(m);
// Set the prototype explicitly.
Object.setPrototypeOf(this, MsgError.prototype);
}
sayHello() {
return "hello " + this.message;
}
}
2
3
4
5
6
7
8
9
10
11
12
However, any subclass of MsgError will have to manually set the prototype as well. For runtimes that don’t support Object.setPrototypeOf, you may instead be able to use proto. 但是,MsgError 的任何子类都必须手动设置原型。对于不支持 Object.setPrototypeOf 的运行时,您可以使用 _ proto _。
Unfortunately, these workarounds will not work on Internet Explorer 10 and prior. One can manually copy methods from the prototype onto the instance itself (i.e. MsgError.prototype onto this), but the prototype chain itself cannot be fixed. 不幸的是,这些变通方法不会在 Internet Explorer 10 和之前起作用。人们可以手动地将方法从原型复制到实例本身 (例如,MsgError.prototype 复制到实例本身) ,但是原型链本身不能修复。
# Member Visibility 会员能见度
- public: A public member can be accessed anywhere. public 成员可以在任何地方访问。
- protected: protected members are only visible to subclasses of the class they’re declared in. 受保护成员只对它们在其中声明的类的子类可见。
- exposure of 曝光 protected members 成员:Derived classes need to follow their base class contracts, but may choose to expose a subtype of base class with more capabilities. This includes making protected members public。派生类需要遵循其基类契约,但可以选择公开具有更多功能的基类的子类型。这包括使受保护成员公开。
- private:private is like protected, but doesn’t allow access to the member even from subclasses.Private 类似于 protected,但是不允许访问成员,即使是来自子类。
- Cross-instance 交叉实例 private access 访问:
Different OOP languages disagree about whether different instances of the same class may access each others’ private members. While languages like Java, C#, C++, Swift, and PHP allow this, Ruby does not. 不同的 OOP 语言对同一类的不同实例是否可以访问彼此的私有成员存在分歧。尽管 Java、 c # 、 c + + 、 Swift 和 PHP 等语言允许这样做,但 Ruby 不允许。TypeScript does allow cross-instance private access.TypeScript 允许跨实例的私有访问
private and protected are only enforced during type checking.private 和 protected 只在类型检查期间强制执行。
private also allows access using bracket notation during type checking. This makes private-declared fields potentially easier to access for things like unit tests, with the drawback that these fields are soft private and don’t strictly enforce privacy. Private 还允许在类型检查期间使用括号表示法访问。这使得私有声明的字段可能更容易访问像单元测试这样的东西,但缺点是这些字段是软私有的,并不严格执行隐私。
Unlike TypeScripts’s private, JavaScript’s private fields (#) remain private after compilation and do not provide the previously mentioned escape hatches like bracket notation access, making them hard private. 与 TypeScripts 的私有字段不同,JavaScript 的私有字段 (#) 在编译后仍然是私有的,并且不提供前面提到的逃逸字段,比如括号记号访问,这使得它们很难私有化。
When compiling to ES2021 or less, TypeScript will use WeakMaps in place of #. 当编译成 es2021 或更少时,打字稿将使用 WeakMaps 来代替 # 。
If you need to protect values in your class from malicious actors, you should use mechanisms that offer hard runtime privacy, such as closures, WeakMaps, or private fields. Note that these added privacy checks during runtime could affect performance. 如果需要保护类中的值不受恶意操作者的攻击,应该使用提供硬运行时隐私的机制,如闭包、 WeakMaps 或私有字段。请注意,运行时期间这些添加的隐私检查可能会影响性能。
# Static Members 固定成员
Classes may have static members. These members aren’t associated with a particular instance of the class. They can be accessed through the class constructor object itself。类可以有静态成员。这些成员不与类的特定实例关联。它们可以通过类构造函数对象本身访问。
Static members can also use the same public, protected, and private visibility modifiers。 静态成员还可以使用相同的 public、 protected 和 private 可见性修饰符。
Static members are also inherited。 静态成员也可以继承。
# Special Static Names 特殊静态名称
It’s generally not safe/possible to overwrite properties from the Function prototype. Because classes are themselves functions that can be invoked with new, certain static names can’t be used. Function properties like name, length, and call aren’t valid to define as static members。 从函数原型中覆盖属性通常是不安全的 / 不可能的。因为类本身是可以用新名称调用的函数,所以某些静态名称不能使用。函数属性,如名称、长度和调用,无法定义为静态成员。
# Why No Static Classes? 为什么没有静态类?
we don’t need a “static class” syntax in TypeScript because a regular object (or even top-level function) will do the job just as well. 我们不需要打字稿中的 “静态类” 语法,因为一个常规对象 (甚至是顶级函数) 也可以很好地完成这项工作。
# static Blocks in Classes 类中的块
Static blocks allow you to write a sequence of statements with their own scope that can access private fields within the containing class. This means that we can write initialization code with all the capabilities of writing statements, no leakage of variables, and full access to our class’s internals. 静态块允许您编写具有自己作用域的语句序列,该语句序列可以访问包含类中的私有字段。这意味着我们可以使用编写语句的所有功能来编写初始化代码,不泄露变量,并且可以完全访问类的内部。
# Generic Classes 通用类
Classes can use generic constraints and defaults the same way as interfaces. 类可以像使用接口一样使用泛型约束和默认值。
# Type Parameters in Static Members 静态成员中的类型参数
The static members of a generic class can never refer to the class’s type parameters. 泛型类的静态成员永远不能引用类的类型参数。
# this at Runtime in Classes 在运行时在类中
Long story short, by default, the value of this inside a function depends on how the function was called. In this example, because the function was called through the obj reference, its value of this was obj rather than the class instance. 长话短说,默认情况下,这个函数在函数内部的值取决于函数的调用方式。在这个例子中,因为函数是通过 obj 引用调用的,所以它的值是 obj 而不是类实例。
# Arrow Functions 箭头函数
If you have a function that will often be called in a way that loses its this context, it can make sense to use an arrow function property instead of a method definition: 如果你有一个函数被调用的方式会失去它的上下文,那么使用箭头函数属性来代替方法定义是有意义的:
class MyClass {
name = "MyClass";
getName = () => {
return this.name;
};
}
const c = new MyClass();
const g = c.getName;
// Prints "MyClass" instead of crashing
console.log(g());
2
3
4
5
6
7
8
9
10
This has some trade-offs: 这有一些取舍:
The this value is guaranteed to be correct at runtime, even for code not checked with TypeScript 这个值在运行时保证是正确的,即使对于没有用打字稿检查的代码也是如此
This will use more memory, because each class instance will have its own copy of each function defined this way 这将使用更多的内存,因为每个类实例都有以这种方式定义的每个函数的自己的副本
You can’t use super.getName in a derived class, because there’s no entry in the prototype chain to fetch the base class method from 不能在派生类中使用 super.getName,因为原型链中没有从中提取基类方法的条目
# this parameters 参数
In a method or function definition, an initial parameter named this has special meaning in TypeScript. These parameters are erased during compilation 在方法或函数定义中,名为 this 的初始参数在打字稿中具有特殊意义。这些参数在编译过程中被删除
TypeScript checks that calling a function with a this parameter is done so with a correct context. Instead of using an arrow function, we can add a this parameter to method definitions to statically enforce that the method is called correctly. 打字稿检查使用 this 参数调用函数是否使用了正确的上下文。与使用箭头函数不同,我们可以在方法定义中添加 this 参数来静态地强制方法被正确调用。
This method makes the opposite trade-offs of the arrow function approach: 这个方法使得箭头函数的取舍相反:
JavaScript callers might still use the class method incorrectly without realizing it JavaScript 调用方可能仍然不正确地使用类方法而没有实现它
Only one function per class definition gets allocated, rather than one per class instance 每个类定义只分配一个函数,而不是每个类实例分配一个函数
Base method definitions can still be called via super. 仍然可以通过 super 调用基方法定义
# this Types 类类型
In classes, a special type called this refers dynamically to the type of the current class. 在类中,一个名为 this 的特殊类型动态地引用当前类的类型。
# this-based type guards 基于类型的保护
You can use this is Type in the return position for methods in classes and interfaces. When mixed with a type narrowing (e.g. if statements) the type of the target object would be narrowed to the specified Type. 您可以在类和接口中的方法的返回位置中使用这个是 Type。当与类型收缩 (例如 if 语句) 混合时,目标对象的类型将收缩到指定的 Type。
A common use-case for a this-based type guard is to allow for lazy validation of a particular field. 此类型保护的一个常见用例是允许对特定字段进行延迟验证。
class Box<T> {
value?: T;
hasValue(): this is { value: T } {
return this.value !== undefined;
}
}
2
3
4
5
6
7
# Parameter Properties 参数属性
TypeScript offers special syntax for turning a constructor parameter into a class property with the same name and value. These are called parameter properties and are created by prefixing a constructor argument with one of the visibility modifiers public, private, protected, or readonly. The resulting field gets those modifier(s): 打字稿提供了特殊的语法,可以将构造函数参数转换为具有相同名称和值的类属性。这些属性称为参数属性,通过在构造函数参数前加上一个可见性修饰符 public、 private、 protected 或 readonly 来创建。结果字段得到这些修饰符:
class Params {
constructor(
public readonly x: number,
protected y: number,
private z: number
) {
// No body necessary
}
}
2
3
4
5
6
7
8
9
# Class Expressions 类别表达式
Class expressions are very similar to class declarations. The only real difference is that class expressions don’t need a name, though we can refer to them via whatever identifier they ended up bound to: 类表达式与类声明非常相似。唯一的区别是类表达式不需要名称,尽管我们可以通过它们最终绑定到的任何标识符引用它们.
const someClass = class<Type> {
content: Type;
constructor(value: Type) {
this.content = value;
}
};
const m = new someClass("Hello, world");
2
3
4
5
6
7
8
# abstract Classes and Members 班级及成员
Classes, methods, and fields in TypeScript may be abstract. 打字稿中的类、方法和字段可能是抽象的。
An abstract method or abstract field is one that hasn’t had an implementation provided. These members must exist inside an abstract class, which cannot be directly instantiated. 抽象方法或抽象字段是没有提供实现的方法。这些成员必须存在于抽象类中,而抽象类不能直接实例化。
The role of abstract classes is to serve as a base class for subclasses which do implement all the abstract members. When a class doesn’t have any abstract members, it is said to be concrete. 抽象类的作用是作为实现所有抽象成员的子类的基类。当一个类没有任何抽象成员时,它被称为具体的。
# Abstract Construct Signatures 抽象构造签名
function greet(ctor: new () => Base) {
const instance = new ctor();
instance.printName();
}
2
3
4
# Relationships Between Classes 阶级之间的关系
In most cases, classes in TypeScript are compared structurally, the same as other types. 在大多数情况下,TypeScript 中的类在结构上进行比较,与其他类型相同。
class Point1 {
x = 0;
y = 0;
}
class Point2 {
x = 0;
y = 0;
}
// OK
const p: Point1 = new Point2();
2
3
4
5
6
7
8
9
10
11
12
Similarly, subtype relationships between classes exist even if there’s no explicit inheritance: 类似地,即使没有明确的继承,类之间也存在子类型关系:
class Person {
name: string;
age: number;
}
class Employee {
name: string;
age: number;
salary: number;
}
// OK
const p: Person = new Employee();
2
3
4
5
6
7
8
9
10
11
12
13
Empty classes have no members. In a structural type system, a type with no members is generally a supertype of anything else. So if you write an empty class (don’t!), anything can be used in place of it. 空类没有成员。在结构类型系统中,没有成员的类型通常是其他任何类型的超类型。因此,如果您编写了一个空类 (不要!) 任何东西都可以代替它.