在接触 ts 相关代码的过程中,总能看到 interface 和 type 的身影。只记得,曾经遇到 type 时不懂查阅过,记得他们很像,相同的功能用哪一个都可以实现。但最近总看到他们,就想深入的了解一下他们。

interface:接口

TypeScript 的核心原则之一是对值所具有的结构进行类型检查。 而接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。

interface LabelledValue {
label: string;
} function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
} let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);

接口就好比一个名字,用来描述上面例子里的要求。

接口具有的特性:

  • 可选属性
interface SquareConfig {
color?: string;
}
  • 只读属性
interface Point {
readonly x: number;
}
  • 多余属性检查,防止使用不属于接口的属性
interface Preson {
name: string;
age?: number;
} let p1:Person = {name: '小明'} // 正确
let p2:Person = {name: '小明', age: 18, sex: '男'}; // 报错 // 绕过:多余属性不报错
// 方式1
let p = {name: '小明', age: 18, sex: '男'};
let p3 = p; // 方式2
interface Preson {
name: string;
age?: number;
[propName: string]: any
}
let p4 = {name: '小明', age: 18, sex: '男'};
  • 函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
  • 索引类型: 针对数组
interface StringArray {
[index: number]: string;
} let myArray: StringArray;
myArray = ["Bob", "Fred"];
  • 类类型

    • 类实现接口
    interface ClockInterface {
    currentTime: Date;
    setTime(d: Date);
    } class Clock implements ClockInterface {
    currentTime: Date;
    setTime(d: Date) {
    this.currentTime = d;
    }
    constructor(h: number, m: number) { }
    }
    • 接口继承接口,可多个
    interface Shape {
    color: string;
    } interface PenStroke {
    penWidth: number;
    } interface Square extends Shape, PenStroke {
    sideLength: number;
    } let square = <Square>{};
    square.color = "blue";
    square.sideLength = 10;
    square.penWidth = 5.0;

type:类型别名

type 会给一个类型起个新名字。 type 有时和 interface 很像,但是可以作用于原始值(基本类型),联合类型,元组以及其它任何你需要手写的类型。

举例:

type Name = string; // 基本类型
type NameResolver = () => string; // 函数
type NameOrResolver = Name | NameResolver; // 联合类型 function getName(n: NameOrResolver): Name {
if (typeof n === 'string') {
return n;
} else {
return n();
}
}

起别名不会新建一个类型 - 它创建了一个新 名字来引用那个类型。给基本类型起别名通常没什么用,尽管可以做为文档的一种形式使用。

同接口一样,类型别名也可以是泛型 - 我们可以添加类型参数并且在别名声明的右侧传入:

type Container<T> = { value: T };

也可以使用类型别名来在属性里引用自己:

type Tree<T> = {
value: T;
left: Tree<T>;
right: Tree<T>;
}

与交叉类型一起使用,我们可以创建出一些十分稀奇古怪的类型。

type LinkedList<T> = T & { next: LinkedList<T> };

interface Person {
name: string;
} var people: LinkedList<Person>;
var s = people.name;
var s = people.next.name;
var s = people.next.next.name;
var s = people.next.next.next.name;

然而,类型别名不能出现在声明右侧的任何地方。

type Yikes = Array<Yikes>; // error

interface vs type

1. Objects / Functions

两者都可以用来描述对象或函数的类型,但是语法不同。

Interface

interface Point {
x: number;
y: number;
} interface SetPoint {
(x: number, y: number): void;
}

Type alias

type Point = {
x: number;
y: number;
}; type SetPoint = (x: number, y: number) => void;

2. Other Types

与接口不同,类型别名还可以用于其他类型,如基本类型(原始值)、联合类型、元组。

// primitive
type Name = string; // object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; }; // union
type PartialPoint = PartialPointX | PartialPointY; // tuple
type Data = [number, string]; // dom
let div = document.createElement('div');
type B = typeof div;

3. Extend

两者都可以扩展,但是语法又有所不同。此外,请注意接口和类型别名不是互斥的。接口可以扩展类型别名,反之亦然。

Interface extends interface

interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }

Type alias extends type alias

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

Interface extends type alias

type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }

Type alias extends interface

interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };

4. class Implements

类可以以相同的方式实现接口或类型别名。但是请注意,类和接口被认为是静态的。因此,它们不能实现/扩展命名联合类型的类型别名。

interface Point {
x: number;
y: number;
} class SomePoint implements Point {
x: 1;
y: 2;
} type Point2 = {
x: number;
y: number;
}; class SomePoint2 implements Point2 {
x: 1;
y: 2;
} type PartialPoint = { x: number; } | { y: number; }; // FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
x: 1;
y: 2;
}

5. extends class

类定义会创建两个东西:类的实例类型和一个构造函数。 因为类可以创建出类型,所以你能够在允许使用接口的地方使用类。

class Point {
x: number;
y: number;
} interface Point3d extends Point {
z: number;
}

6. Declaration merging

与类型别名不同,接口可以定义多次,并将被视为单个接口(合并所有声明的成员)。

// These two declarations become:
// interface Point { x: number; y: number; }
interface Point { x: number; }
interface Point { y: number; } const point: Point = { x: 1, y: 2 };

7. 计算属性,生成映射类型

type 能使用 in 关键字生成映射类型,但 interface 不行。

语法与索引签名的语法类型,内部使用了 for .. in。 具有三个部分:

  • 类型变量 K,它会依次绑定到每个属性。
  • 字符串字面量联合的 Keys,它包含了要迭代的属性名的集合。
  • 属性的结果类型。
type Keys = "firstname" | "surname"

type DudeType = {
[key in Keys]: string
} const test: DudeType = {
firstname: "Pawel",
surname: "Grzybek"
} // 报错
//interface DudeType2 {
// [key in keys]: string
//}

7. 其他细节

export default interface Config {
name: string
} // export default type Config1 = {
// name: string
// }
// 会报错 type Config2 = {
name: string
}
export default Config2

总结

interface 和 type 很像,很多场景,两者都能使用。但也有细微的差别:

  • 类型:对象、函数两者都适用,但是 type 可以用于基础类型、联合类型、元祖。
  • 同名合并:interface 支持,type 不支持。
  • 计算属性:type 支持, interface 不支持。

总的来说,公共的用 interface 实现,不能用 interface 实现的再用 type 实现。主要是一个项目最好保持一致。

参考:

【区分】Typescript 中 interface 和 type的更多相关文章

  1. TypeScript中的private、protected

    首先我们要清楚 private . protected 现阶段只是javascript中的保留字(Reserved words),而非关键字(Keywords ).因此TypeScript中的纯类型声 ...

  2. 5种在TypeScript中使用的类型保护

    摘要:在本文中,回顾了TypeScript中几个最有用的类型保护,并通过几个例子来了解它们的实际应用. 本文分享自华为云社区<如何在TypeScript中使用类型保护>,作者:Ocean2 ...

  3. TypeScript 中的方法重载

    方法重载(overload)在传统的静态类型语言中是很常见的.JavaScript 作为动态语言, 是没有重载这一说的.一是它的参数没有类型的区分,二是对参数个数也没有检查.虽然语言层面无法自动进行重 ...

  4. 十分钟教你理解TypeScript中的泛型

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.原文出处:https://blog.bitsrc.io/understanding-generics-in-t ...

  5. TypeScript中使用getElementXXX()

    如果只是看解决方法,可以直接跳到第二小节 简述 Angular 1.x版本是用JavaScript编写的,我们在百度Angular经常会搜索到AngularJS,并不是JavaScript的什么衍生版 ...

  6. 聊聊 TypeScript 中的类型保护

    聊聊 TypeScript 中的类型保护 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 lay ...

  7. typescript 中的 infer 关键字的理解

    infer 这个关键字,整理记录一下,避免后面忘记了.有点难以理解呢. infer infer 是在 typescript 2.8中新增的关键字. infer 可以在 extends 条件类型的字句中 ...

  8. TypeScript 中命名空间与模块的理解?区别?

    一.模块 TypeScript 与ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块 相反地,如果一个文件不带有顶级的import或者expo ...

  9. typescript中对象属性可选属性与只读属性与索引签名

    可选属性 type类型别名 type 会给一个类型起个新名字. type 有时和 interface 很像,但是可以作用于原始值(基本类型),联合类型,元组以及其它任何你需要手写的类型. interf ...

随机推荐

  1. QT5.1编译后的安装目录问题(硬路径问题)

    这个是我的编译参数:configure -ltcg -confirm-license -opensource -platform win32-msvc2010 -debug-and-release - ...

  2. python requests模块session的使用建议及整个会话中的所有cookie的方法

    话不多说,直接上代码 测试代码 服务端 下面是用flask做的一个服务端,用来设置cookie以及打印请求时的请求头 # -*- coding: utf-8 -*- from flask import ...

  3. mvc中Scripts.Render的用法

    第一次接触新的东西,都会很陌生,但是时间久了就熟悉了变简单了. 视图文件中使用Scripts.Render()输出脚本包,Styles.Render()输出样式包 上面两张图是我所做项目里的,放上面会 ...

  4. 深入理解计算机系统 BombLab 实验报告

    又快有一个月没写博客了,最近在看<深入理解计算机系统>这本书,目前看完了第三章,看完这章,对程序的机器级表示算是有了一个入门,也对 C 语言里函数栈帧有了一个初步的理解. 为了加深对书本内 ...

  5. Hexo+NexT(六):手把手教你编写一个Hexo过滤器插件

    Hexo+NexT介绍到这里,我认为已经可以很好地完成任务了.它所提供的一些基础功能及配置,都已经进行了讲解.你已经可以随心所欲地配置一个自己的博客环境,然后享受码字的乐趣. 把博客托管到Github ...

  6. JVM(七):JVM内存结构

    JVM(七):JVM内存结构 在前几节的文章我们多次讲到 Class 对象需要分配入 JVM 内存,并在 JVM 内存中执行 Java 代码,完成对象内存的分配.执行.回收等操作,因此,如今让我们来走 ...

  7. iOS开发(5):设备唯一标识与全局变量

    这里记录两个iOS开发中经常用到的知识点,一个是唯一标识,一个是全局变量. (1)唯一标识 唯一标识一台设备(比如iPhone.iPad等)是一个基本的实现与业务上的需求,因为这个唯一标识在许多场景都 ...

  8. 【记录】Mysql数据库更新主键自增

    语法:id从1000开始自增: ALTER TABLE 表名 AUTO_INCREMENT = 1000;

  9. Python批量自动裁剪图片

    """用Pythonp批量裁剪图片""" from PIL import Image import matplotlib.pyplot as ...

  10. 2018.11.2 2018NOIP冲刺之最短公共父串

    很有意思的一个题 试题描述 给定字符串A和字符串B,要求找一个最短的字符串,使得字符串A和B均是它的子序列. 输入 输入包含两行,每行一个字符串,分别表示字符串A和字符串B.(串的长度不超过30) 输 ...