⚡️typescript学习笔记【第三课】type 和 interface

303 阅读3分钟

Type aliases and interfaces are very similar, and in many cases you can choose between them freely. Almost all features of an interface are available in type, the key distinction is that a type cannot be re-opened to add new properties vs an interface which is always extendable.

  • 别名和接口是类似的,在很多情况下我们可以自由选择typeinterface
  • 几乎interface的所有特性都可以用type实现。
  • 主要的不同就是type不可以重新添加属性,接口可以扩展。

type 类型别名

type alias is exactly that - a name for any type.

类型别名其实就是一个类型的名称。

type name = string;
type ID = string | number;
type tag = string[];

type Person = {
    userName: name;
    idCard: ID;
    tags: tag;
    age: number;
}
type Feature = {
    complexion: string;
    gender: string;
    interest: string[];
}
type PersonFeature = Person & Feature

const someone: PersonFeature = {
    userName: '大脚',
    idCard: '1101011000010',
    tags: ['演员', '乡村爱情'],
    age: 18,
    complexion: '黄',
    gender: '女',
    interest: ['嚼舌根', '二人转']
}

interface 接口

An interface declaration is another way to name an object type:

接口声明是对对象类型的另一种命名方式。

interface PersonFeature {
    userName: name;
    idCard: ID;
    tags: tag;
    age: number;
    complexion: string;
    gender: string;
    interest: string[];
}

相同点

都可以用来定义对象或函数类型,只是语法不同。

// type 
type alignment = 'left' | 'right' | 'center';
type PrintText = (s: string, align: alignment) => void;
const printFun: PrintText = (s: string, align: 'left' | 'right' | 'center') => {
    console.log(s, align);
};
printFun('a', 'left');

// interface
type alignment = 'left' | 'right' | 'center';
interface PrintText {
    (s: string, align: alignment): void;
}
const printFun: PrintText = (s: string, align: 'left' | 'right' | 'center') => {
    console.log(s, align);
};
printFun('a', 'left');

都可以扩展

💡 typeinterface可以相互继承

  1. interface继承

    interface Person {
        userName: name;
        idCard: ID;
        tags: tag;
        age: number;
    }
    interface PersonFeature extends Person {
        complexion: string;
        gender: string;
        interest: string[];
    }
    
    
    type Person = {
        userName: name;
        idCard: ID;
        tags: tag;
        age: number;
    }
    interface PersonFeature extends Person {
        complexion: string;
        gender: string;
        interest: string[];
    }
    
  2. type继承

    type Person = {
        userName: name;
        idCard: ID;
        tags: tag;
        age: number;
    }
    type PersonFeature = Person & {
        complexion: string;
        gender: string;
        interest: string[];
    }
    
    interface Person {
        userName: name;
        idCard: ID;
        tags: tag;
        age: number;
    }
    type PersonFeature = Person & {
        complexion: string;
        gender: string;
        interest: string[];
    }
    

不同点

type 可以基本数据类型、联合类型、元组

type strType = string;
type Person = { name: string } | { idCard: number | string };
type twoDays = [string, number];

以上用interface不可以实现。

interface 声明合并

interface Person {
    userName: string;
}
interface Person {
    gender: string;
}

const dajiao: Person = {
    userName: '谢大脚',
    gender: '女'
}

多次生命同一个接口,TS会将他们合并成一个声明, 如果使用type会报错 Duplicate identifier 'Person'

一个例子

interface MyInterface {
    footbar: string;
}
type MyType = {
    footbar: string;
};
const exampleInterface: MyInterface = { footbar: 'hello' };
const exampleType: MyType = { footbar: 'hello' };

let record: Record<string, string>;
record = exampleType;
record = exampleInterface; // Index signature for type 'string' is missing in type 'MyInterface'.

Record<string,string>{[key:string]:string}相同。只有当该类型的所有属性都已知并且可以对照该索引签名进行检查时,才允许将子集分配给该索引签名类型。在您的例子中,从exampleTypeRecord<string,string>的所有内容都是可分配的。这只能针对对象字面量类型进行检查,因为一旦声明了对象字面量类型,就无法更改它们。因此,索引签名是已知的。

相反,在你使用interface去声明变量时,它们在那一刻类型并不是最终的类型。由于interfac可以进行声明合并,所以总有可能将新成员添加到同一个interface定义的类型上。

type计算属性、interface索引属性

type 可以使用 in 关键字来生成映射,用来限定对象类型key的取值范围

type personKeys = "name" | "age"

type personType = {
    [key in personType]: string
}

const testPerson: personType = {
    name: "test",
    age: "Grzybek"
}

// 报错 'personKeys' only refers to a type, but is being used as a value here.
//interface testPerson2 {
//  [key in personType]: string
//}

如何选择

推荐使用interface,无法满足需求的情况再使用type

开发库时使用interface,类型合并可更加灵活的扩展未知的复杂场景。