我最近遇到了这个问题,我不确定是使用接口还是使用类来定义特定类型。
注意:这个问题不是 ,而是询问
之间的区别class
和interface
例如,给定此类和接口
interface IMyClass {
foo: string;
bar: () => string;
}
class MyClass implements IMyClass {
foo = 'foo';
bar() {
return 'bar';
}
}
我将使用类或接口作为函数参数中的类型。
function identityByClass(value: MyClass): MyClass {
return value;
}
function identityByInterface(value: IMyClass): IMyClass {
return value;
}
从我的角度来看,我认为两者都不错,但我更喜欢使用该类来避免同步接口上的所有方法/属性。我认为界面只是类必须遵守的模板/合同。
但是,就我而言,大多数情况下,该类通常会添加更多不在接口定义上的方法/属性。
在这种情况下,下面是此类。
class MyClassPlus implements IMyClass {
foo = 'foo';
bar() {
return 'bar';
}
doMore() {
console.log('more stuff here!');
}
}
在这种情况下,我不能再将两者互换使用。
任何指向最佳做法的链接也将很不错。谢谢。
答案 0 :(得分:1)
使用接口定义类型所获得的一个好处是,编译后就消除了接口本身。这样可以减少应用程序的整体膨胀,这是在这种情况下使用接口的有力依据。
您可能会发现这很有用:https://jameshenry.blog/typescript-classes-vs-interfaces/
答案 1 :(得分:1)
我不确定是否要使用接口或类来定义特定类型。
两个类和接口都创建一个类型,因此原则上它们可以互换使用。正如您所指出的,接口就像公共合同,而类则实现此合同。
但请考虑以下情况:
MyClass
,怎么办?MyClass
通过揭示这是一个类类型来公开更多实现细节。重构的MyClass
的新类型签名可能不再有效,不能用作函数identityByClass
中的函数参数。因此,您需要重构所有使用者-嗯...使用separate type interface,这种情况不太可能发生。
第2点的示例:客户可以想到获取MyClass
的静态属性的想法(接口通过隐藏实现细节而使其不明显):
class MyClass {
static baz(){}
foo = 'foo';
}
function identityByClass(value: MyClass) {
console.log((value.constructor as any).baz) // function baz()
// there we go. do something with static baz() method of MyClass
}
顺便说一句:它不仅涉及接口和类类型。 Type aliases提供强大的功能,例如映射或条件类型,并集等,并且大多数时候都可用于支持接口。
但是,就我而言,大多数情况下,该类通常会添加更多不在接口定义上的方法/属性。
您不需要同步类和接口类型。为了保持DRY,我想到了两个选择:
与第二个观点相比,我更倾向于第二点,因为它遵循Information Hiding或Loose coupling之类的设计原则。示例:
class MyClass {
foo = 'foo';
tooMuchDetail = "hide me"
}
// just pick, what we need (foo here)
type OnlyNeededProps = Pick<MyClass, "foo">
function doSomethingWithFoo(a: OnlyNeededProps) {
a.foo
a.tooMuchDetail // error, unknown (OK)
}
doSomethingWithFoo(new MyClass())