泛型、接口、type理解

1、type VS interface

官方解释:

An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.

An interface can have multiple merged declarations, but a type alias for an object type literal cannot.

翻译下的意思就是:

1、interface可以用extends继承,同时定义的接口能用于类实现,而type不行。

2、interface能用于能够声明合并,而type不行。

具体例子就是:

interface使用extends继承

interface Name { 
  name: string; 
}

interface User extends Name { 
  age: number; 
}


interface用于实现

interface Name { 
  name: string; 
}

class MyName implements Name {
  name: string; // Same as Name
}


interface合并

interface User {
  name: string
  age: number
}

interface User {
  sex: string
}

/*
User 接口为 {
  name: string
  age: number
  sex: string 
}
*/


上面只是说了哪些interface能使用而type不能使用的场景,下面详细说下它们之间的异同点。

都可以描述函数和对象

  • 描叙对象
interface:

interface User {
  name: string
}

type:

type User = {
  name: string
}


  • 描叙函数
interface:

interface getName {
    (id:string):string
}

type:

type getName = (id:string)=>string

都可以扩展

interface:

interface Name {
  name: string
}

interface User extends Name { 
  age: number; 
}


type:

type Name  = {
    name:string
}

type User = Name &{
    age: number; 
}

而且还能相互扩展

type Name  = {
    name:string
}

interface User extends Name { 
  age: number; 
}

type能做而interface不行的

  • 我们应该发现interface只能用于对象或者函数类型定义,而不能对基础类型进行定义(其实也没有任何必要),但是对定义联合类型还是很有用的

// 基本类型别名
type Name = string (意义不大)

// 联合类型
type StringOrNumber = string | number;  

// 元组
type PetList = [Dog, Pet]


2、对泛型的理解

首先我们得想想typescript中为什么要用到泛型,官方的解释是:

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

简单一个例子,假如我们有一个通用的队列class,在这个队列里面我们定义一些通用对方法:


class List{
    private data = [];
    public push (item){
        this.data.push(item)
    }
}


这个List我们不知道它对data是什么类型,可能是string,也可能是number是无法确定,我们可能现传入了一个string类型,后面又传入了一个number类型,这不是ts期望的。

 let aList = new List();
 alist.push(1);
 alist.push('2');

但是如果我们提前定义好data的类型为string,这样如果我们需要一个number类型的队列的时候就需要在一个。


class List{
    private data:Array<string> = [];
    public push (item:string){
        this.data.push(item)
    }
}

这个时候泛型就发挥作用了,它的存在就是“不预先指定具体的类型,而在使用的时候再指定类型的一种特性”


class List<T>{
    private data:Array<T> = [];
    public push (item:T){
        this.data.push(item)
    }
}


let aList = new List<string>();
alist.push('1');
alist.push('2');
alist.push(3); //error


使用场景

  • 泛型函数

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


let a = backValue<string>(1)//error

let b = backValue<string>('1')

  • 泛型类(见上文)

  • 泛型接口


interface GenericIdentityFn<T> {
    (arg: T): T;
}

let fn:GenericIdentityFn<string> = (arg)=>{
    return arg
}


泛型参数

我们可以随意定义自己对泛型参数(T),泛型常用 T、U、V 表示.

泛型 VS any

declare function fn<T>(arg: T): void;

declare function fn(arg: any): void;

在这里,泛型完全没有必要使用,因为它仅用于单个参数的位置

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。