定义类和成员
class Point {
x: number
y: number
constructor(x : number, y : number){
this.x = x
this.y = y
}
public add(p : Point) : Point {
return new Point(p.x + this.x, p.y + this.y)
}
}
const p = new Point(0, 0)
const newP = p.add(new Point(1, 1))
console.log(newP)
成员函数的重载
class Point {
// ...
public add(x : number, y : number) : Point;
public add(p : Point) : Point;
public add(x : number | Point, y? : number) {
if(typeof x === 'number') {
return new Point(this.x + x , this.y + y!)
}
const p = x
return new Point(this.x + p.x, this.y + p.y)
}
}
const p = new Point(0, 0)
const newP = p.add(new Point(1, 1))
console.log(newP)
重载可以获得更好的书写提示体验。
Getter / Setter
获取和设置变成两个方法,隐藏了内部具体的实现。
class C {
_length = 0;
get length() {
return this._length;
}
set length(value) {
this._length = value;
}
}
不推荐这样的实现,推荐:
可读性,语义更强
class C {
_length = 0;
getLength() {
return this._length;
}
setLength(value) {
this._length = value;
}
}
索引器
class Arr<T> {
[i : number] : T
}
const a = new Arr<number>()
a[10] = 100
console.log(a[10]) // 100
类型继承
interface BasicAddress {
name?: string;
street: string;
city: string;
country: string;
postalCode: string;
}
interface AddressWithUnit extends BasicAddress {
unit: string;
}
类的继承
class Animal {
move() {
console.log("Moving along!");
}
}
class Dog extends Animal {
woof(times: number) {
for (let i = 0; i < times; i++) {
console.log("woof!");
}
}
}
实战中尽量使用组合:
interface Movable {
move() : void;
}
class Dog implements Movable {
move () {
console.log('move dog')
}
}
或者泛型:
class Movable<T extends Animal> {
animal : T
move(){
console.log(`${animal.getName()} is moving`)
}
}
划重点:继承会加重耦合,组合和泛型不会。
成员可见域
- public
- protected
- private
`public` `private` `protected` 这3个和其他语言一样,具体的:
`public` 成员允许所有程序访问,如果不标识任何约束,那么默认就是`public`
class Point {
x : number
}
// x可以被任意程序访问
`private` 成员只允许在当前类中访问。
class Point {
private x : number
constructor(){
this.x = x // 成立
}
getX(){
return this.x
}
}
const p = new Point()
console.log(p.x)
// Error : Property 'x' is private and only accessible within class 'Point'.ts(2341)
`protected` 允许在当前类和它的继承类中访问成员。
class Animal {
private _name1;
protected _name2;
}
class Dog extends Animal{
getName1(){
return this._name1 // Error
}
getName2(){
return this._name2 // pass
}
}
静态成员
class MyClass {
static x = 0;
static printX() {
console.log(MyClass.x);
}
}
console.log(MyClass.x);
MyClass.printX();
静态成员和类的实例没有关系,静态成员、静态方法都绑定在类型本身上。
静态成员也会继承:
class Base {
static getGreeting() {
return "Hello world";
}
}
class Derived extends Base {
myGreeting = Derived.getGreeting();
}
保留的特殊静态成员名称:
class S {
static name = "S!";
// Error : Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'S'.
}
为什么没有静态类?
在 Java中有静态类, 静态类是相对类的嵌套的概念,在JS虽然也存在类的嵌套,但是遵循闭包的逻辑,比如:
class A {
x : number
foo(){
const y = 0
class B{
bar(){
this.x // Property 'x' does not exist on type 'B'
console.log(y)
}
}
return B
}
}
因为有B包的逻辑,就不太适合再增加,让嵌套类可以访问外部类成员的逻辑了。 逻辑太复杂,不利于程序员写程序。
类型守卫
class FileSystemObject {
isFile(): this is FileRep {
return this instanceof FileRep;
}
isDirectory(): this is Directory {
return this instanceof Directory;
}
isNetworked(): this is Networked & this {
return this.networked;
}
constructor(public path: string, private networked: boolean) {}
}
class FileRep extends FileSystemObject {
constructor(path: string, public content: string) {
super(path, false);
}
}
class Directory extends FileSystemObject {
children: FileSystemObject[];
}
interface Networked {
host: string;
}
const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");
if (fso.isFile()) {
fso.content;
//const fso: FileRep
} else if (fso.isDirectory()) {
fso.children;
//const fso: Directory
} else if (fso.isNetworked()) {
fso.host;
//const fso: Networked & FileSystemObject
}
抽象类
抽象类不可以实例化
abstract class Base {
abstract getName(): string;
printName() {
console.log("Hello, " + this.getName());
}
}
const b = new Base();
// Cannot create an instance of an abstract class.
必须继承:
class Derived extends Base {
getName() {
return "world";
}
}
const d = new Derived();
d.printName();
类型的关系
TS会通过成员去思考类型是否一致:
class Point1 {
x = 0;
y = 0;
}
class Point2 {
x = 0;
y = 0;
}
// OK
const p: Point1 = new Point2();
另一个例子:
class Person {
name: string;
age: number;
}
class Employee {
name: string;
age: number;
salary: number;
}
// OK
const p: Person = new Employee();
最后一个例子:
class Empty {}
function fn(x: Empty) {
// can't do anything with 'x', so I won't
}
// All OK!
fn(window);
fn({});
fn(fn);
1