本文主要是介绍精进TypeScript--你了解类型(type)和接口(interface)的区别吗?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
要记住的事情:
- 理解 type 和 interface 之间的异同
- 知道如何使用其中一种语法来编写相同的类型
- 当决定在你的项目中使用哪一种语法时,既要考虑既定的风格,也要考虑扩增是否会有好处
如果你想在 TypeScript 中定义一个命名类型,你有两种选择,使用一个类型或接口,如下:
type TState = {name: string;capital: string;
}interface IState {name: string;capital: string;
}
你应该使用哪个?你应该意识到 type 和 interface 之间的区别,并且在哪种情况下使用哪一种都要保持一致。但是,你也应该知道如何使用这两种方式来编写相同的类型,这样你就能自如地读懂使用这两种编写的 TypeScript 代码。
首先,关于相似性:State 类型之间几乎没有区别。不管你用 IState 还是 TState 定义了一个带有多余属性的值,你得到的错误是字对字相同的:
const state: TState = {name: 'China';capital: 'BeiJing';population: 5000000; // ~~ 不能将类型 ... 分配给类型 “TState”
}
你可以对 interface 和 type 使用索引签名:
type TDict = {[key: string]: string};
interface IDict {[key: string]: string;
}
你也可以用它们中的任意一个定义函数类型:
type TFn = (x: number) => string;
interface IFn {(x: number): string;
}const toStrT: TFn = x => '' + x; // OK
const toStrI: IFn = x => '' + x; // OK
对于这种直接的函数类型,类型别名看起来更自然,但如果函数类型也具有属性,那么声明看起来就更相似。
type TFnWithProperties = {(x: number): number;prop: string;
}
interface IFnWithProperties {(x: number): number;prop: string;
}
你可以通过提醒自己,在JavaScript 中,函数是可调用的对象,来记住这种语法。
类型别名和接口都可以是泛型:
type TPair<T> = {first: T;second: T;
}interface IPair<T> = {first: T;second: T;
}
interface 可以扩展 type,type 也可以扩展 interface:
interface IStateWithPop extends TState {population: number;
}
type TStateWithPop = IState & {population: number;}
同样,这两个类型都是相同的。需要注意的是,interface 不能扩展复杂的类型,如联合类型。如果你想这么做,你需要使用 type 和 &。
类(class)可以实现interface或简单类型:
class StateT implements TState {name: string = '';capital: string = '';
}
class StateI implements IState {name: string = '';capital: string = '';
}
这些是相似之处。那不同之处呢?你已经看到了一个:有联合 type,但没有联合 interface:
type A or B = 'a' | 'b';
扩展联合类型是很有用的。如果你有单独的 Input 和 Output 变量的类型,以及从名字(name)到变量的映射:
type Input = { /*...*/ };
type Output = { /*...*/ };
interface VariableMap {[name: string]: Input | Output;
}
那么你可能想要一个将名字(name)附加到变量上的类型,如:
type NamedVariable = (Input | Output) & {name: string};
这个类型无法用 interface 来表达。一般来说,type 比 interface 能力更强。类型可以是一个联合类型,也可以利用更高级的特性,如映射类型(mapped)和条件类型(conditional)。
它还可以更容易地表达元组和数组类型:
type Pair = [number, number];
type StringList = string[];
type NamedNums = [string, ...number[]];
你可以用 interface 来表达类似元组的东西:
interface Tuple {0: number;1: number;length: 2;
}
const t: Tuple = [10, 20]; // OK
但这很笨拙,而且放弃了所有的元组方法,如 concat,所以最好使用 type。
不过,interface 确实有一些 type 没有的能力。其中之一就是 interface 可以被扩增。比如:
interface IState {name: string;capital: string;
}
interface IState {population: number;
}
const state: IState = {name: 'China';capital: 'BeiJing';population: 5000000;
}; // OK
这就是所谓的 “声明合并” ,如果你从来没见过这种写法,它会让你很惊讶。它主要用于类型声明文件,如果你正在编写一个类型声明文件,你就应该遵循该规范,并使用 interface 来支持它。这样做,是因为你的类型声明中可能会缺少一些需要用户补充的属性,这时候用户就会使用声明合并。
对于没有既定风格的项目,你应该考虑扩增。你是否在为一个 API 发布类型声明?如果 API 发生变化时,能够通过 interface 合并新的字段可能对你的用户有帮助,那就使用 interface。但是,对于一个在你项目内部使用的类型,声明合并可能是一个错误,那就倾向于使用 type。
这篇关于精进TypeScript--你了解类型(type)和接口(interface)的区别吗?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!