【区分】Typescript 中 interface 和 type
在接触 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: Interfaces vs Types
- TYPESCRIPT INTERFACE VS. TYPE
【区分】Typescript 中 interface 和 type的更多相关文章
- TypeScript中的private、protected
首先我们要清楚 private . protected 现阶段只是javascript中的保留字(Reserved words),而非关键字(Keywords ).因此TypeScript中的纯类型声 ...
- 5种在TypeScript中使用的类型保护
摘要:在本文中,回顾了TypeScript中几个最有用的类型保护,并通过几个例子来了解它们的实际应用. 本文分享自华为云社区<如何在TypeScript中使用类型保护>,作者:Ocean2 ...
- TypeScript 中的方法重载
方法重载(overload)在传统的静态类型语言中是很常见的.JavaScript 作为动态语言, 是没有重载这一说的.一是它的参数没有类型的区分,二是对参数个数也没有检查.虽然语言层面无法自动进行重 ...
- 十分钟教你理解TypeScript中的泛型
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.原文出处:https://blog.bitsrc.io/understanding-generics-in-t ...
- TypeScript中使用getElementXXX()
如果只是看解决方法,可以直接跳到第二小节 简述 Angular 1.x版本是用JavaScript编写的,我们在百度Angular经常会搜索到AngularJS,并不是JavaScript的什么衍生版 ...
- 聊聊 TypeScript 中的类型保护
聊聊 TypeScript 中的类型保护 在 TypeScript 中使用联合类型时,往往会碰到这种尴尬的情况: interface Bird { // 独有方法 fly(); // 共有方法 lay ...
- typescript 中的 infer 关键字的理解
infer 这个关键字,整理记录一下,避免后面忘记了.有点难以理解呢. infer infer 是在 typescript 2.8中新增的关键字. infer 可以在 extends 条件类型的字句中 ...
- TypeScript 中命名空间与模块的理解?区别?
一.模块 TypeScript 与ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块 相反地,如果一个文件不带有顶级的import或者expo ...
- typescript中对象属性可选属性与只读属性与索引签名
可选属性 type类型别名 type 会给一个类型起个新名字. type 有时和 interface 很像,但是可以作用于原始值(基本类型),联合类型,元组以及其它任何你需要手写的类型. interf ...
随机推荐
- qt中用tcp传输xml消息 good
本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环境: 主机:WIN7 开发环境:Qt5 3.1.2 说明: 在tcp上传输xml消息. 协议格式如 ...
- UILabel实现自适应宽高需要注意的地方(二)
需求图如下所示 UILabel "上期" 距离屏幕最左边 有35px UILabel "下期" 距离屏幕最右边 有35px 进行中文字在UIlabe ...
- Silverlight ItemsControl详细解析+解惑
Silverlight最强大的地方就在于定义控件了,Silverlight提供了非常灵活和高效的控件定义方式,几乎可以实现任何复杂的控件实现,对于快速开发应用程序有着重要的意义.在Silverligh ...
- python读取json文件并解析
# -*- coding: utf-8 -*- import os import json import sys reload(sys) sys.setdefaultencoding('utf-8') ...
- Spark之权威指南经典案例
hadoop权威指南上有一个求历史最高温度的经典案例,源数据如下: -- sample.txt0067011990999991950051507004+68750+023550FM-12+038299 ...
- String的所有方法以及解释
capitalize() 把字符串的第一个字符改为大写 casefold() 把整个字符串的所有字符改为小写 center(width) 将字符串居中,并使用空格填充至长度 width 的新字符串 c ...
- Zookeeper详解-工作流和leader选举(三)
一.工作流 一旦ZooKeeper集合启动,它将等待客户端连接.客户端将连接到ZooKeeper集合中的一个节点.它可以是leader或follower节点.一旦客户端被连接,节点将向特定客户端分配会 ...
- ios开发系列之内存泄漏分析(上)
ios自从引入ARC机制后,一般的内存管理就可以不用我们码农来负责了,但是一些操作如果不注意,还是会引起内存泄漏. 本文主要介绍一下内存泄漏的原理.常规的检测方法以及出现的常用场景和修改方法. 1. ...
- SQL经典练习题50--mysql
--1.学生表 Student(Sid,Sname,Sage,Ssex)? --Sid 学生编号,Sname 学生姓名,Sage 出生年月,Ssex 学生性别 --2.课程表? Course(Cid, ...
- SLAM方向国内有哪些优秀公司?
计算机视觉life为读者整理了国内几十家涉及SLAM的优秀公司,涵盖自动驾驶.仓储机器人.服务机器人.无人机.AR.芯片相机等领域. 一 自动/辅助驾驶: 1.百度: 主要产品:自动驾驶软件 百度智能 ...