在接触 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. Bokeh 0.9.0dev 发布,交互式可视化库

    快速使用Romanysoft LAB的技术实现 HTML 开发Mac OS App,并销售到苹果应用商店中.   <HTML开发Mac OS App 视频教程> 土豆网同步更新:http: ...

  2. 基于Delphi实现客户端服务端通信Demo

    在开始之前我们需要了解下这个Demo功能是啥 我们可以看到这是两个小project,左边的project有服务端和客户端1,右边的project只有一个客户端2 效果就是当两个客户端各自分别输入正确的 ...

  3. Dependency Injection 筆記 (4)

    续上集未完的相关设计模式... (本文摘自電子書:<.NET 依賴注入> Composite 模式 延续先前的电器比喻.现在,如果希望 UPS 不只接计算机,还要接电风扇.除湿机,可是 U ...

  4. 转载几篇文章URL

    读了百伯在线Jobbole的几篇文章,转给需要的朋友.如下: 产品小设计大体验:http://blog.jobbole.com/39593/ 苹果是一家有工程师的设计公司:Google是一家有设计师的 ...

  5. 通往Google之路:***

    *** & BBR 安装 系统支持:CentOS 6+, Debian 7+, Ubuntu 12+ 内存要求:≥128M --- 前提 满足以上要求的VPS服务器一台 安装基础命令工具:yu ...

  6. spark 2.x在windows环境使用idea本地调试启动了kerberos认证的hive

    1 概述 开发调试spark程序时,因为要访问开启kerberos认证的hive/hbase/hdfs等组件,每次调试都需要打jar包,上传到服务器执行特别影响工作效率,所以调研了下如何在window ...

  7. JVM 参数类型

    标准参数 -help -server -client -version -showversion -cp -classpath X参数 非标准化参数(在各个JDK版本中可能会变,但是变动比较小) -X ...

  8. Storm 学习之路(一)—— Storm和流处理简介

    一.Storm 1.1 简介 Storm 是一个开源的分布式实时计算框架,可以以简单.可靠的方式进行大数据流的处理.通常用于实时分析,在线机器学习.持续计算.分布式RPC.ETL等场景.Storm具有 ...

  9. PyCharm2018 汉化&激活

    一.汉化 将下载好的resources_cn_PyCharm_2018.1_r2.jar 放入pycharm 的lib 目录中,启动app即可 下载链接: https://pan.baidu.com/ ...

  10. Linux查看进程具体开启时间

    ps -p 2417 -o lstart -- 2417为进程号