is/are 在 Typescript 中导出接口的目的是什么?
What is/are the purpose(s) in exporting an interface in Typescript?
Typescript 新手。我可以看到您可以定义一个接口并在整个 Typescript 项目中使用它。我可以看到许多描述如何 "export" 界面的博客、教程和文档。但是,我不明白你为什么要这样做。我当然可以理解导出 类 或常量或变量....但是导出接口有什么好处呢?好像需要的时候可以随时参考使用?
显然我遗漏了一个关键概念,非常感谢您提供的任何清晰或见解。
编译安全
您可以导出一个接口,以便可以将其导入另一个 class,后者将实现它。这样你就可以获得围绕接口契约的类型安全。
假设您有一个界面 IPerson
(抱歉陈词滥调!)
export interface IPerson {
getFirstName(): string;
getLastName(): string;
getAgeInYears(): number;
}
现在您对该接口进行了具体实现,称为 Person
,但实际上并未引用该接口:
export class Person {
private _firstName: string;
private _lastName: string;
private _ageInYears: number;
constructor (firstName: string, lastName: string, ageInYears: number) {
this._firstName = firstName;
this._lastName = lastName;
this._ageInYears = ageInYears;
}
public getFirstName(): string {
return this._firstName;
}
public getLastName(): string {
return this._lastName;
}
public getAgeInYears(): number{
return this._ageInYears;
}
}
您的 class 将正常运行,并且具有 IPerson
的所有预期行为,但是如果您随后向 IPerson
接口添加另一个方法(例如 getFirstPetName(): string
),您的项目仍将继续构建(这可能会导致意外行为)。
这可以通过显式导入接口并使 Person
实现它来解决,这样除非 Person
符合合同,否则您的项目将无法构建。
import { IPerson } from "./person.i";
export class Person implements IPerson {
// ...
}
依赖抽象
通过导出一个接口,它可以被其他地方导入并依赖,而不是你的程序依赖具体的实现。 (这是dependency inversion principle)
如果你有一个函数 getPersonFullName
接受一个 Person
:
getPersonFullName(person: Person) {
return person.getFirstName() + " " + person.getLastName();
}
这将无法用于 IPerson
的其他实现,即使它们满足相同的合同和要求(例如,如果您制作了 IFictionalPerson
)。
通过导入 IPerson
并依赖它,您可以确保您的函数将适用于 IPerson
的任何实现,而不是特定的 Person
实现。
import { IPerson } from "./person.i";
getPersonFullName(person: IPerson) {
return person.getFirstName() + " " + person.getLastName();
}
您可能想要导出它,以便您可以使用它来模拟某种数据格式,这样您就可以在 IDE 中自动完成并在编译期间进行类型检查。
我自己在不需要完全成熟的情况下就这样做了 class 所以我使用接口来描述数据对象的外观,这样我在开发过程中就可以减少猜测。接口未编译成 Javascript 并丢失。它们仅在编译期间或 IDE 开发期间有用。
It seems like you can always use it by reference if necessary?
全球接口无处不在。要制作全局接口,只需将代码放在没有顶级 import
和 export
关键字的 TypeScript 文件中。
但是,就像老式的全局变量一样,全局接口也存在命名冲突。导出的接口解决了这个问题。
示例:
// a.ts
export interface A {}
export default let a: A;
// b.ts
import b, {A as B} from './a'
// Here, the name of A is B
Typescript 新手。我可以看到您可以定义一个接口并在整个 Typescript 项目中使用它。我可以看到许多描述如何 "export" 界面的博客、教程和文档。但是,我不明白你为什么要这样做。我当然可以理解导出 类 或常量或变量....但是导出接口有什么好处呢?好像需要的时候可以随时参考使用?
显然我遗漏了一个关键概念,非常感谢您提供的任何清晰或见解。
编译安全
您可以导出一个接口,以便可以将其导入另一个 class,后者将实现它。这样你就可以获得围绕接口契约的类型安全。
假设您有一个界面 IPerson
(抱歉陈词滥调!)
export interface IPerson {
getFirstName(): string;
getLastName(): string;
getAgeInYears(): number;
}
现在您对该接口进行了具体实现,称为 Person
,但实际上并未引用该接口:
export class Person {
private _firstName: string;
private _lastName: string;
private _ageInYears: number;
constructor (firstName: string, lastName: string, ageInYears: number) {
this._firstName = firstName;
this._lastName = lastName;
this._ageInYears = ageInYears;
}
public getFirstName(): string {
return this._firstName;
}
public getLastName(): string {
return this._lastName;
}
public getAgeInYears(): number{
return this._ageInYears;
}
}
您的 class 将正常运行,并且具有 IPerson
的所有预期行为,但是如果您随后向 IPerson
接口添加另一个方法(例如 getFirstPetName(): string
),您的项目仍将继续构建(这可能会导致意外行为)。
这可以通过显式导入接口并使 Person
实现它来解决,这样除非 Person
符合合同,否则您的项目将无法构建。
import { IPerson } from "./person.i";
export class Person implements IPerson {
// ...
}
依赖抽象
通过导出一个接口,它可以被其他地方导入并依赖,而不是你的程序依赖具体的实现。 (这是dependency inversion principle)
如果你有一个函数 getPersonFullName
接受一个 Person
:
getPersonFullName(person: Person) {
return person.getFirstName() + " " + person.getLastName();
}
这将无法用于 IPerson
的其他实现,即使它们满足相同的合同和要求(例如,如果您制作了 IFictionalPerson
)。
通过导入 IPerson
并依赖它,您可以确保您的函数将适用于 IPerson
的任何实现,而不是特定的 Person
实现。
import { IPerson } from "./person.i";
getPersonFullName(person: IPerson) {
return person.getFirstName() + " " + person.getLastName();
}
您可能想要导出它,以便您可以使用它来模拟某种数据格式,这样您就可以在 IDE 中自动完成并在编译期间进行类型检查。
我自己在不需要完全成熟的情况下就这样做了 class 所以我使用接口来描述数据对象的外观,这样我在开发过程中就可以减少猜测。接口未编译成 Javascript 并丢失。它们仅在编译期间或 IDE 开发期间有用。
It seems like you can always use it by reference if necessary?
全球接口无处不在。要制作全局接口,只需将代码放在没有顶级 import
和 export
关键字的 TypeScript 文件中。
但是,就像老式的全局变量一样,全局接口也存在命名冲突。导出的接口解决了这个问题。
示例:
// a.ts
export interface A {}
export default let a: A;
// b.ts
import b, {A as B} from './a'
// Here, the name of A is B