typeScript中的extends关键字怎么使用

发布时间:2023-02-14 09:45:34 作者:iii
来源:亿速云 阅读:273

TypeScript中的extends关键字怎么使用

TypeScript是一种由微软开发的开源编程语言,它是JavaScript的一个超集,添加了可选的静态类型和基于类的面向对象编程。TypeScript的设计目标是开发大型应用,它可以编译成纯JavaScript,运行在任何浏览器、任何计算机和任何操作系统上。

在TypeScript中,extends关键字是一个非常重要的概念,它在多种场景下都有广泛的应用。本文将详细介绍extends关键字在TypeScript中的使用方式,包括类继承、接口扩展、泛型约束等。

目录

  1. 类继承
  2. 接口扩展
  3. 泛型约束
  4. 条件类型
  5. 高级类型
  6. 总结

类继承

在面向对象编程中,继承是一个核心概念。TypeScript通过extends关键字支持类的继承。通过继承,子类可以继承父类的属性和方法,并且可以添加新的属性和方法,或者重写父类的方法。

基本语法

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    move(distance: number = 0) {
        console.log(`${this.name} moved ${distance}m.`);
    }
}

class Dog extends Animal {
    bark() {
        console.log('Woof! Woof!');
    }
}

const dog = new Dog('Rex');
dog.move(10); // Rex moved 10m.
dog.bark(); // Woof! Woof!

在这个例子中,Dog类继承了Animal类。Dog类不仅可以使用Animal类的move方法,还可以定义自己的bark方法。

方法重写

子类可以重写父类的方法,以满足特定的需求。

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    move(distance: number = 0) {
        console.log(`${this.name} moved ${distance}m.`);
    }
}

class Snake extends Animal {
    move(distance: number = 5) {
        console.log('Slithering...');
        super.move(distance);
    }
}

const snake = new Snake('Sammy');
snake.move(); // Slithering... Sammy moved 5m.

在这个例子中,Snake类重写了Animal类的move方法,并在其中调用了super.move(distance),以保留父类的行为。

构造函数中的super

在子类的构造函数中,必须调用super()来初始化父类的属性。

class Animal {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    move(distance: number = 0) {
        console.log(`${this.name} moved ${distance}m.`);
    }
}

class Horse extends Animal {
    constructor(name: string) {
        super(name); // 必须调用super()
    }

    move(distance: number = 45) {
        console.log('Galloping...');
        super.move(distance);
    }
}

const horse = new Horse('Tommy');
horse.move(34); // Galloping... Tommy moved 34m.

在这个例子中,Horse类的构造函数中调用了super(name),以确保Animal类的name属性被正确初始化。

接口扩展

在TypeScript中,接口(Interface)用于定义对象的形状。通过extends关键字,一个接口可以扩展另一个接口,从而继承其属性和方法。

基本语法

interface Person {
    name: string;
    age: number;
}

interface Employee extends Person {
    employeeId: number;
}

const employee: Employee = {
    name: 'John',
    age: 30,
    employeeId: 12345
};

在这个例子中,Employee接口扩展了Person接口,因此Employee接口包含了Person接口的所有属性,并且添加了employeeId属性。

多重扩展

一个接口可以同时扩展多个接口。

interface Person {
    name: string;
    age: number;
}

interface Employee {
    employeeId: number;
}

interface Manager extends Person, Employee {
    department: string;
}

const manager: Manager = {
    name: 'Alice',
    age: 35,
    employeeId: 67890,
    department: 'HR'
};

在这个例子中,Manager接口同时扩展了PersonEmployee接口,因此Manager接口包含了PersonEmployee接口的所有属性,并且添加了department属性。

接口扩展类

在TypeScript中,接口不仅可以扩展其他接口,还可以扩展类。当一个接口扩展一个类时,它会继承类的成员,但不包括其实现。

class Person {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    greet() {
        console.log(`Hello, my name is ${this.name}`);
    }
}

interface Employee extends Person {
    employeeId: number;
}

const employee: Employee = {
    name: 'John',
    employeeId: 12345,
    greet() {
        console.log(`Hello, my name is ${this.name} and my employee ID is ${this.employeeId}`);
    }
};

employee.greet(); // Hello, my name is John and my employee ID is 12345

在这个例子中,Employee接口扩展了Person类,因此Employee接口包含了Person类的name属性和greet方法。需要注意的是,接口扩展类时,不会继承类的实现,因此Employee接口中的greet方法需要重新定义。

泛型约束

在TypeScript中,泛型(Generics)允许我们创建可重用的组件,这些组件可以处理多种类型的数据。通过extends关键字,我们可以对泛型进行约束,以确保泛型参数符合特定的条件。

基本语法

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

const output = identity<string>('Hello');
console.log(output); // Hello

在这个例子中,identity函数是一个泛型函数,它可以接受任何类型的参数,并返回相同类型的值。通过<T>语法,我们定义了一个泛型参数T

泛型约束

有时候,我们希望泛型参数只能是某些特定的类型。这时,我们可以使用extends关键字对泛型进行约束。

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length); // 现在我们知道arg有length属性
    return arg;
}

loggingIdentity('Hello'); // 5
loggingIdentity([1, 2, 3]); // 3
loggingIdentity({ length: 10, value: 'Hello' }); // 10

在这个例子中,loggingIdentity函数的泛型参数T被约束为必须实现Lengthwise接口的类型。因此,arg参数必须具有length属性。

多重约束

一个泛型参数可以同时满足多个约束条件。

interface Lengthwise {
    length: number;
}

interface Printable {
    print(): void;
}

function loggingIdentity<T extends Lengthwise & Printable>(arg: T): T {
    console.log(arg.length); // 现在我们知道arg有length属性
    arg.print(); // 现在我们知道arg有print方法
    return arg;
}

const obj = {
    length: 10,
    print() {
        console.log('Printing...');
    }
};

loggingIdentity(obj); // 10, Printing...

在这个例子中,loggingIdentity函数的泛型参数T被约束为必须同时实现LengthwisePrintable接口的类型。因此,arg参数必须具有length属性和print方法。

泛型约束与类

泛型约束也可以应用于类。

class Person {
    name: string;

    constructor(name: string) {
        this.name = name;
    }

    greet() {
        console.log(`Hello, my name is ${this.name}`);
    }
}

class Employee extends Person {
    employeeId: number;

    constructor(name: string, employeeId: number) {
        super(name);
        this.employeeId = employeeId;
    }

    work() {
        console.log(`${this.name} is working.`);
    }
}

function printEmployee<T extends Person>(employee: T): void {
    employee.greet();
    if (employee instanceof Employee) {
        employee.work();
    }
}

const employee = new Employee('John', 12345);
printEmployee(employee); // Hello, my name is John, John is working.

在这个例子中,printEmployee函数的泛型参数T被约束为必须继承Person类的类型。因此,employee参数必须具有greet方法。如果employeeEmployee类的实例,还可以调用work方法。

条件类型

在TypeScript中,条件类型(Conditional Types)允许我们根据类型之间的关系来选择不同的类型。条件类型通常与extends关键字一起使用。

基本语法

type IsString<T> = T extends string ? true : false;

type A = IsString<string>; // true
type B = IsString<number>; // false

在这个例子中,IsString是一个条件类型,它根据T是否扩展string类型来选择truefalse

分布式条件类型

当条件类型应用于联合类型时,它会自动分发到联合类型的每个成员上。

type ToArray<T> = T extends any ? T[] : never;

type A = ToArray<string | number>; // string[] | number[]

在这个例子中,ToArray条件类型被应用于string | number联合类型,因此结果是string[] | number[]

条件类型与泛型约束

条件类型可以与泛型约束结合使用,以实现更复杂的类型逻辑。

type NonNullable<T> = T extends null | undefined ? never : T;

type A = NonNullable<string | number | null | undefined>; // string | number

在这个例子中,NonNullable条件类型用于过滤掉nullundefined类型。

条件类型与映射类型

条件类型还可以与映射类型结合使用,以实现更灵活的类型转换。

type FunctionPropertyNames<T> = {
    [K in keyof T]: T[K] extends Function ? K : never;
}[keyof T];

type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>;

class Person {
    name: string;
    age: number;
    greet() {
        console.log(`Hello, my name is ${this.name}`);
    }
}

type PersonFunctionProperties = FunctionProperties<Person>; // { greet: () => void }

在这个例子中,FunctionPropertyNames条件类型用于提取Person类中所有方法的名称,然后FunctionProperties映射类型用于提取这些方法。

高级类型

在TypeScript中,extends关键字还可以用于定义高级类型,如交叉类型、联合类型、映射类型等。

交叉类型

交叉类型(Intersection Types)是将多个类型合并为一个类型。

interface Person {
    name: string;
    age: number;
}

interface Employee {
    employeeId: number;
}

type EmployeePerson = Person & Employee;

const employeePerson: EmployeePerson = {
    name: 'John',
    age: 30,
    employeeId: 12345
};

在这个例子中,EmployeePerson类型是PersonEmployee类型的交叉类型,因此它包含了PersonEmployee接口的所有属性。

联合类型

联合类型(Union Types)表示一个值可以是多种类型之一。

type StringOrNumber = string | number;

function printValue(value: StringOrNumber) {
    console.log(value);
}

printValue('Hello'); // Hello
printValue(123); // 123

在这个例子中,StringOrNumber类型表示一个值可以是stringnumber类型。

映射类型

映射类型(Mapped Types)允许我们基于现有类型创建新类型。

type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

type Person = {
    name: string;
    age: number;
};

type ReadonlyPerson = Readonly<Person>;

const person: ReadonlyPerson = {
    name: 'John',
    age: 30
};

// person.name = 'Alice'; // Error: Cannot assign to 'name' because it is a read-only property.

在这个例子中,Readonly映射类型用于将Person类型的所有属性设置为只读。

条件映射类型

条件映射类型结合了条件类型和映射类型,允许我们根据条件选择不同的映射方式。

type NonNullablePropertyKeys<T> = {
    [K in keyof T]: T[K] extends null | undefined ? never : K;
}[keyof T];

type NonNullableProperties<T> = Pick<T, NonNullablePropertyKeys<T>>;

type Person = {
    name: string;
    age: number | null;
    address: string | undefined;
};

type NonNullablePerson = NonNullableProperties<Person>; // { name: string }

在这个例子中,NonNullablePropertyKeys条件映射类型用于提取Person类型中所有非null和非undefined属性的名称,然后NonNullableProperties映射类型用于提取这些属性。

总结

在TypeScript中,extends关键字是一个非常重要的概念,它在类继承、接口扩展、泛型约束、条件类型和高级类型中都有广泛的应用。通过extends关键字,我们可以实现代码的复用、类型的安全性和灵活性。

掌握extends关键字的使用,可以帮助我们编写更加灵活、安全和可维护的TypeScript代码。希望本文对你理解和使用extends关键字有所帮助。

推荐阅读:
  1. 测试如何防范xss
  2. Nessus在centos上面的应用

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

typescript extends

上一篇:MySQL中的数据存储结构是什么

下一篇:Node常见的安全处理方法有哪些

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》