interface User { name: string age: number } type User = { name: string age: number }; interface SetUser { (name: string, age: number): void; } type SetUser = (name: string, age: number): void;
都允许拓展(extends):
interface 和 type 都可以拓展,并且两者并不是相互独立的,也就是说 interface 可以 extends type , type 也可以 extends interface 。 虽然效果差不多,但是两者语法不同 。
interface extends interface
interface Name { name: string; } interface User extends Name { age: number; }
type extends type
type Name = { name: string; } type User = Name & { age: number };
interface extends type
type Name = { name: string; } interface User extends Name { age: number; }
type extends interface
interface Name { name: string; } type User = Name & { age: number; }
2. 不同点
type 可以而 interface 不行
type 可以声明基本类型别名,联合类型,元组等类型
// 基本类型别名 type Name = string // 联合类型 interface Dog { wong(); } interface Cat { miao(); } type Pet = Dog | Cat // 具体定义数组每个位置的类型 type PetList = [Dog, Pet]
type 语句中还可以使用 typeof 获取实例的 类型进行赋值
// 当你想获取一个变量的类型时,使用 typeof let div = document.createElement('div'); type B = typeof div
其他骚操作
type StringOrNumber = string | number; type Text = string | { text: string }; type NameLookup = Dictionary<string, Person>; type Callback<T> = (data: T) => void; type Pair<T> = [T, T]; type Coordinates = Pair<number>; type Tree<T> = T | { left: Tree<T>, right: Tree<T> };
interface 可以而 type 不行
interface 能够声明合并
interface User { name: string age: number } interface User { sex: string } /* User 接口为 { name: string age: number sex: string } */
interface 有可选属性和只读属性
可选属性
接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。 例如给函数传入的参数对象中只有部分属性赋值了。带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个 ? 符号。如下所示
interface Person { name: string; age?: number; gender?: number; }
只读属性
顾名思义就是这个属性是不可写的,对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly 来指定只读属性,如下所示:
interface User { readonly loginName: string; password: string; }
上面的例子说明,当完成User对象的初始化后loginName就不可以修改了。
3.4 实现与继承: implements vs extends
extends 很明显就是ES6里面的类继承,那么 implement 又是做什么的呢?它和 extends 有什么不同?
implement ,实现。与C#或Java里接口的基本作用一样, TypeScript 也能够用它来明确的强制一个类去符合某种契约
implement基本用法:
interface IDeveloper { name: string; age?: number; } // OK class dev implements IDeveloper { name = 'Alex'; age = 20; } // OK class dev2 implements IDeveloper { name = 'Alex'; } // Error class dev3 implements IDeveloper { name = 'Alex'; age = '9'; }
而 extends 是继承父类,两者其实可以混着用:
class A extends B implements C,D,E
搭配 interface 和 type 的用法有:
3.5 声明文件与命名空间: declare 和 namespace
前面我们讲到Vue项目中的 shims-tsx.d.ts 和 shims-vue.d.ts ,其初始内容是这样的:
// shims-tsx.d.ts import Vue, { VNode } from 'vue'; declare global { namespace JSX { // tslint:disable no-empty-interface interface Element extends VNode {} // tslint:disable no-empty-interface interface ElementClass extends Vue {} interface IntrinsicElements { [elem: string]: any; } } } // shims-vue.d.ts declare module '*.vue' { import Vue from 'vue'; export default Vue; }
declare :当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
这里列举出几个常用的:
declare var 声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare global 扩展全局变量
declare module 扩展模块
namespace :“内部模块”现在称做“命名空间”
module X { 相当于现在推荐的写法 namespace X { )
跟其他 JS 库协同
类似模块,同样也可以通过为其他 JS 库使用了命名空间的库创建 .d.ts 文件的声明文件,如为 D3 JS 库,可以创建这样的声明文件:
declare namespace D3{ export interface Selectors { ... } } declare var d3: D3.Base;
所以上述两个文件:
shims-tsx.d.ts , 在全局变量 global 中批量命名了数个内部模块。 shims-vue.d.ts ,意思是告诉 TypeScript *.vue 后缀的文件可以交给 vue 模块来处理。
3.6 访问修饰符: private 、 public 、 protected
其实很好理解:
默认为 public
当成员被标记为 private 时,它就不能在声明它的类的外部访问,比如:
class Animal { private name: string; constructor(theName: string) { this.name = theName; } } let a = new Animal('Cat').name; //错误,‘name'是私有的
protected 和 private 类似,但是, protected 成员在派生类中可以访问