TypeScript语法 中级篇

来源:互联网 发布:java构造器使用实例 编辑:程序博客网 时间:2024/05/23 17:14

泛型

下面来创建第一个使用泛型的例子:identity函数。 这个函数会返回任何传入它的值。

不用泛型的话,这个函数可能是下面这样:

function identity(arg: number): number {    return arg;}

或者,我们使用any类型来定义函数:

function identity(arg: any): any {    return arg;}

虽然使用any类型后这个函数已经能接收任何类型的arg参数,但是却丢失了一些信息:传入的类型与返回的类型应该是相同的。 如果我们传入一个数字,我们只知道任何类型的值都有可能被返回。

因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。

function identity<T>(arg: T): T {    return arg;}

看似与泛型方法类似,但是还是有区别的。比如如下例子:

  // 方法一:带有any参数的方法  function any_func(arg: any): any {      console.log(arg.length);      return arg;  }  // 方法二:Array泛型方法  function array_func<T>(arg: Array<T>): Array<T> {      console.log(arg.length);  // Error: T doesn't have .length     return arg; }

联合类型

偶尔你会遇到这种情况,一个代码库希望传入 number或string类型的参数。 例如下面的函数:

 function padLeft(value: string, padding: any) {    if (typeof padding === "number") {        return Array(padding + 1).join(" ") + value;    }    if (typeof padding === "string") {        return padding + value;    }    throw new Error(`Expected string or number, got '${padding}'.`);}padLeft("Hello world", 4); // returns "    Hello world"let indentedString = padLeft("Hello world", true); // 编译阶段通过,运行时报错
function padLeft(value: string, padding: string | number) {    // ...}let indentedString = padLeft("Hello world", true); // errors during compilation

高级类型

交叉类型(Intersection Types)
交叉类型是将多个类型合并为一个类型。 这让我们可以把现有的多种类型叠加到一起成为一种类型,它包含了所需的所有类型的特性。 例如, Person & Serializable & Loggable同时是Person和Serializable和Loggable。 就是说这个类型的对象同时拥有了这三种类型的成员。

我们大多是在混入(mixins)或其它不适合典型面向对象模型的地方看到交叉类型的使用。 (在JavaScript里发生这种情况的场合很多!) 下面是如何创建混入的一个简单例子:

function extend<T, U>(first: T, second: U): T & U {    let result = <T & U>{};    for (let id in first) {        (<any>result)[id] = (<any>first)[id];    }    for (let id in second) {        if (!result.hasOwnProperty(id)) {            (<any>result)[id] = (<any>second)[id];        }    }    return result;}class Person {    constructor(public name: string) { }}interface Loggable {    log(): void;}class ConsoleLogger implements Loggable {    log() {        // ...    }}var jim = extend(new Person("Jim"), new ConsoleLogger());var n = jim.name;jim.log();

构造函数+static

class Greeter {    static standardGreeting = "Hello, there";    greeting: string;    greet() {        if (this.greeting) {            return "Hello, " + this.greeting;        }        else {            return Greeter.standardGreeting;        }    }}let greeter1: Greeter;greeter1 = new Greeter();console.log(greeter1.greet());let greeterMaker: typeof Greeter = Greeter;greeterMaker.standardGreeting = "Hey there!";let greeter2: Greeter = new greeterMaker();console.log(greeter2.greet());

抽象类

我们可以构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类。
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。 abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法。

abstract class Animal {    abstract makeSound(): void;    move(): void {        console.log('roaming the earch...');    }}

抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。 然而,抽象方法必须包含 abstract关键字并且可以包含访问修饰符。

abstract class Department {    constructor(public name: string) {    }    printName(): void {        console.log('Department name: ' + this.name);    }    abstract printMeeting(): void; // 必须在派生类中实现}class AccountingDepartment extends Department {    constructor() {        super('Accounting and Auditing'); // constructors in derived classes must call super()    }    printMeeting(): void {        console.log('The Accounting Department meets each Monday at 10am.');    }    generateReports(): void {        console.log('Generating accounting reports...');    }}let department: Department; // ok to create a reference to an abstract typedepartment = new Department(); // error: cannot create an instance of an abstract classdepartment = new AccountingDepartment(); // ok to create and assign a non-abstract subclassdepartment.printName();department.printMeeting();department.generateReports(); // error: method doesn't exist on declared abstract type

抽象类与接口的区别

1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

2、抽象类要被子类继承,接口要被类实现。

3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现

4、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。

5、抽象方法只能申明,不能实现

6、抽象类里可以没有抽象方法

7、如果一个类里有抽象方法,那么这个类只能是抽象类

8、抽象方法要被实现,所以不能是静态的,也不能是私有的。

9、接口可继承接口,并可多继承接口,但类只能单根继承。

总结:
1.抽象类 和 接口 都是用来抽象具体对象的. 但是接口的抽象级别最高
2.抽象类可以有具体的方法 和属性, 接口只能有抽象方法和不可变常量
3.抽象类主要用来抽象类别,接口主要用来抽象功能.
4、抽象类中,且不包含任何实现,派生类必须覆盖它们。接口中所有方法都必须是未实现的。

0 0