高德地图打字界面_打字稿界面综合指南

本文深入讲解TypeScript接口的使用方法,包括定义、属性管理及如何处理复杂数据结构。通过实例演示了如何确保类型安全,以及如何灵活运用接口提高代码质量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

高德地图打字界面

There are many reasons to like TypesScript because of the many advantages it has over JavaScript. The primary benefit for most developers is the advantage of type safety. Type safety is accomplished a number of ways within TypeScript, but one of the most important is through interfaces.

有很多理由喜欢TypesScript,因为它比JavaScript具有许多优势。 对于大多数开发人员而言,主要好处是类型安全性的优点。 在TypeScript中,可以通过多种方法来实现类型安全,但是最重要的方法之一是通过接口。

Interfaces allow you to verify that your functions have all the data they need and nothing that they do not need. TypeScript will tell you this all before your code even is compiled.

接口使您可以验证函数是否具有所需的所有数据,而不需要不需要的数据。 TypeScript会在编译代码之前告诉您所有这些信息。

总览 (Overview)

Here is an overview of what this article will cover.

这是本文将介绍的内容的概述。

  • What are TypeScript interfaces?

    什么是TypeScript接口?
  • When do you use TypeScript interfaces?

    什么时候使用TypeScript接口?
  • Simple interface example

    简单的界面示例
  • Adding properties to an interface

    向接口添加属性
  • Removing properties from an interface, and optional properties

    从接口删除属性和可选属性
  • Handling multiple JSON objects

    处理多个JSON对象
  • Handling an array of multiple JSON objects

    处理多个JSON对象的数组
  • Using function properties

    使用函数属性
  • Conclusion and additional resources

    结论和其他资源

什么是TypeScript接口?(What Are TypeScript Interfaces?)

One of the common explanations of TypeScript interfaces is that they define a contract, but what does that mean? It basically means that an interface will specify what properties and what those properties’ type (or types) should be.

TypeScript接口的常见解释之一是它们定义了合同,但这意味着什么? 基本上,这意味着接口将指定什么属性以及那些属性的类型应该是什么。

It’s good to have a small explanation of what interfaces are, but the best way to understand interfaces is through examples and actually using them.

最好对接口是什么进行一些解释,但是了解接口的最佳方法是通过示例并实际使用它们。

什么时候使用TypeScript接口? (When Do You Use TypeScript Interfaces?)

There are a few different ways to use interfaces, but the main two you will see are by using an interface as a parameter to a function and by determining the data structure from something like an API response.

有几种使用接口的方法,但是您将看到的主要两种方法是将接口用作函数的参数,并通过API响应之类的方法确定数据结构。

For this article, we will primarily talk about using an interface as a part of a parameter of a function. The vast majority of times you use an interface, it will be for this use case.

在本文中,我们将主要讨论使用接口作为函数参数的一部分。 您使用接口的绝大多数时间都是针对这种用例。

Later in this article, we will work with JSONPlaceholder and the user endpoint. Here is an example of using our User interface as part of an API response. This a small example from an Angular service.

在本文的后面,我们将使用JSONPlaceholder和用户端点。 这是将我们的User界面用作API响应的一部分的示例。 这是一个来自Angular服务的小例子。

getUsers() {
return this.http.get<User[]>(`https://jsonplaceholder.typicode.com/users`);
}

The above code basically just says to expect the data from that endpoint to conform to the properties and types that were specified in the User interface.

上面的代码基本上只是说要期望来自该端点的数据符合User界面中指定的属性和类型。

简单界面示例 (Simple Interface Example)

In our simple example, we will use just four fields: id, name, username, and email. This interface states that all four fields are required and that the id must be of type number, while the other three must be of type string.

在简单的示例中,我们将仅使用四个字段:id,名称,用户名和电子邮件。 该接口说明所有四个字段都是必填字段,并且id必须为number类型,而其他三个字段必须为string类型。

export interface User {
id: number;
name: string;
username: string;
email: string;
}

Now let’s use this interface in a function.

现在让我们在函数中使用此接口。

const getUser = (user: User) => {
console.log(`This user's name is: ${user.name}`);
};getUser({
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere@april.biz',
});//This user's name is: Leanne Graham

Great! That all worked and was easy.

大! 一切正常,很容易。

向接口添加属性 (Adding Properties to an Interface)

What would happen if you tried to add an additional property not specified in the interface?

如果您尝试添加接口中未指定的其他属性,将会发生什么?

Image for post

As you see above, the first thing that we did was try to add an additionalProperty field to the object passed to getUser. We get the error below.

如上所示,我们所做的第一件事是尝试向传递给getUser的对象添加一个additionalProperty的属性字段。 我们得到下面的错误。

Argument of type '{ id: number; name: string; username: string; email: string; additionalProperty: string; }' is not assignable to parameter of type 'User'.
Object literal may only specify known properties, and 'additionalProperty' does not exist in type 'User'.ts(2345)

This error is just stating that you have added a property, conveniently named additionalProperty, that is not specified in the User interface.

该错误仅表示您已添加一个属性,方便地命名为additionalProperty ,该属性未在User界面中指定。

How do you fix this?

您如何解决这个问题?

You thankfully have two options to resolve this issue.

庆幸的是,您有两个选择可以解决此问题。

1. You could remove additionalProperty from the object being passed into the getUser function. Now that most likely isn’t going to be the solution you are looking for, as you likely intentionally made this change and need the information in the additionalProperty. That said, it does happen that you add properties to an object unintentionally. For example, you may have intended to add the additionalProperty as an additional parameter, not as a property, where the getUser function potentially would look like the following:

1.您可以删除additionalProperty从对象被传递到getUser功能。 现在最有可能的是不会是你正在寻找的解决方案,因为你可能是刻意制造这种变化,需要在信息additionalProperty 。 就是说,您确实无意中向对象添加了属性。 例如,您可能打算将additionalProperty作为附加参数添加, 而不是作为属性, getUser函数的外观可能如下所示:

getUser(
{
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere@april.biz',
},
{ additionalProperty: 'Another one' }
);

2. The other solution would be to update the User interface to account for the new additionalProperty with the appropriate type. Usually, when this error occurs, this is the solution you are looking for.

2.另一种解决方案将是,以更新User界面以考虑新additionalProperty与适当的类型。 通常,发生此错误时,这就是您要寻找的解决方案。

从接口删除属性和可选属性 (Removing Properties From an Interface, and Optional Properties)

So what if we do not need the email property any more?

那么,如果我们不再需要email属性怎么办?

Image for post

As you see, if you just remove the email property from the object passed to getUser, you will see the error below.

如您所见,如果您只是从传递给getUser的对象中删除email属性,则会看到以下错误。

Argument of type ‘{ id: number; name: string; username: string; }’ is not assignable to parameter of type ‘User’.
Property ‘email’ is missing in type ‘{ id: number; name: string; username: string; }’ but required in type ‘User’.ts(2345)interfaces.ts(5, 3): ‘email’ is declared here.

This error is basically saying that email is required to be passed as part of the User interface.

基本上,此错误表示需要email 作为User界面的一部分传递。

How do you fix this?

您如何解决这个问题?

Again, you have two options to fix this.

同样,您有两个选择可以解决此问题。

  1. You could remove email from the User interface. This solution might be fine, but you will need to be certain that the email property would never be added as a property on the object passed to getUser.

    您可以从User界面中删除email 。 这个解决方案可能很好,但是您需要确定email属性永远不会作为传递给getUser的对象的属性添加。

  2. You may have noticed the other solution in the example above, which is to add a ? after email making the property optional. This is a super nice feature of interfaces, allowing the addition or removal of the email property. Of course, you will likely need to make changes within the getUser function to handle the scenario where email is not passed.

    您可能已经注意到上面示例中的另一个解决方案,即添加一个?email后,将该属性设置为可选。 这是界面的超好功能,允许添加或删除email属性。 当然,您可能需要在getUser函数中进行更改以处理未传递email的情况。

处理多个JSON对象 (Handling Multiple JSON Objects)

We’re ramping things up a bit with this example, but let’s take a look at JSONPlaceholder. This an excellent resource for many things in software development, and it will be helpful for explaining TypeScript interfaces as well.

我们通过此示例进行了一些改进,但让我们看一下JSONPlaceholder。 这是软件开发中许多事情的绝佳资源,并且对于解释TypeScript接口也将有所帮助。

We will refer to the users endpoint, and for now we will only look at the first user at this endpoint https://jsonplaceholder.typicode.com/users/1. You can also view this in Chrome, where you should see the JSON structure below.

我们将参考用户端点,现在我们仅查看该端点的第一个用户https://jsonplaceholder.typicode.com/users/1 。 您还可以在Chrom e中查看此内容,在此处应看到下面的JSON结构。

{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "Sincere@april.biz",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
}

How should we go about creating an interface for this? Well, we have a basic idea of how to do this, based on our simple example.

我们应该如何为此创建一个接口? 好吧,基于我们的简单示例,我们对如何执行此操作有基本的了解。

Let’s ignore the address and company objects for now. If we do that, we will have a User interface that looks like the one below.

现在让我们忽略addresscompany对象。 如果这样做,我们将拥有一个类似于以下界面的User界面。

export interface User {
id: number;
name: string;
username: string;
email: string;
phone: string;
website: string;
}

Now how do you accommodate the address and company objects? We will start by creating a new interface for both.

现在,您如何容纳addresscompany对象? 我们将从为两者创建一个新接口开始。

export interface Address {
street: string;
suite: string;
city: string;
zipcode: string;
geo: {
lat: string;
lng: string;
};
}export interface Company {
name: string;
catchPhrase: string;
bs: string;
}

It is generally considered a best practice to create a new interface for each object. You will notice that we neglected to do that for geo object. The reason for this is that this information is likely to always be accompanied by the address information. Of course, if you wanted to, you could create a GeoCoordinates interface and modify the Address interface, like so:

通常,最佳做法是为每个对象创建一个新接口。 您会注意到我们忽略了对geo对象执行此操作。 其原因是该信息很可能总是伴随着地址信息。 当然,如果需要,您可以创建一个GeoCoordinates接口并修改Address接口,如下所示:

interface Address {
street: string;
suite: string;
city: string;
zipcode: string;
geo: GeoCoordinates;
}interface GeoCoordinates {
lat: string;
lng: string;
}

We now have these two new Address and Company interfaces. How do we associate these to the User interface?

现在,我们有了这两个新的AddressCompany接口。 我们如何将它们与User界面关联?

export interface User {
id: number;
name: string;
username: string;
email: string;
address: Address; // uses the new Address interface
phone: string;
website: string;
company: Company; // uses the new Company interface
}

We are at a point now that our User interface is fully set up. Let’s take a look at our updated getUser function.

现在我们已经完全设置了User界面。 让我们看一下更新后的getUser函数。

const logUserAddress = (userAddress: Address) => {
console.log(`The user's address is ${userAddress.street} ${userAddress.suite}`);
};const getUser = (user: User) => {
console.log(`The user's name is ${user.name}`);
console.log(`The user's phone number is ${user.phone}`);
console.log(`The user's zipcode is ${user.address.zipcode}`);
logUserAddress(user.address);
};getUser({
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere@april.biz',
address: {
street: 'Kulas Light',
suite: 'Apt. 556',
city: 'Gwenborough',
zipcode: '92998-3874',
geo: {
lat: '-37.3159',
lng: '81.1496',
},
},
phone: '1-770-736-8031 x56442',
website: 'hildegard.org',
company: {
name: 'Romaguera-Crona',
catchPhrase: 'Multi-layered client-server neural-net',
bs: 'harness real-time e-markets',
},
});//The user's name is Leanne Graham
//The user's phone number is 1-770-736-8031 x56442
//The user's zipcode is 92998-3874
//The user's address is Kulas Light Apt. 556

As you see in the getUser function, the object that is passed is exactly the same as what you saw from https://jsonplaceholder.typicode.com/users/1.

如在getUser函数中看到的,传递的对象与从https://jsonplaceholder.typicode.com/users/1看到的对象完全相同。

One additional change that was made to the getUser function is that there is another function, named logUserAddress, that is getting called within it. This new function takes a parameter of the new Address interface we created. The reason this is nice is that you can only pass the user’s address details with the full benefit of the Address interface and the types definitions of it.

getUser函数进行的另一项logUserAddress是在其中调用了另一个名为logUserAddress函数。 这个新函数采用我们创建的新Address接口的参数。 这样很好的原因是,您只能利用Address接口及其类型定义的全部好处来传递用户的地址详细信息。

处理多个JSON对象的数组 (Handling an Array of Multiple JSON Objects)

So we have ramped things up with the full user object from JSONPlaceholder, but let’s pretend that it’s even a bit more complicated still by adding an array of objects.

因此,我们通过JSONPlaceholder中的完整用户对象来加强了工作,但是我们假设通过添加对象数组,它甚至更加复杂。

Let’s assume our user is rich and has multiple houses, with each house’s details stored in an object within the address array. Your user object is going to look something like the object below.

假设我们的用户很丰富并且有多个房屋,每个房屋的详细信息都存储在address数组中的一个对象中。 您的用户对象将看起来像下面的对象。

{
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere@april.biz',
address: [
{
street: 'Kulas Light',
suite: 'Apt. 556',
city: 'Gwenborough',
zipcode: '92998-3874',
geo: {
lat: '-37.3159',
lng: '81.1496',
},
},
{
street: 'Random Street',
suite: 'Apt. 321',
city: 'Attenborough',
zipcode: '93187-4259',
geo: {
lat: '-37.9911',
lng: '82.0137',
},
},
],
phone: '1-770-736-8031 x56442',
website: 'hildegard.org',
company: {
name: 'Romaguera-Crona',
catchPhrase: 'Multi-layered client-server neural-net',
bs: 'harness real-time e-markets',
},
}

The only changes here are that address is an array and there is a new object with dummy data that matches all of the required properties that are defined in the Address interface.

唯一的变化是address是一个数组,并且存在一个带有伪数据的新对象,该对象与Address接口中定义的所有必需属性相匹配。

{
street: 'Random Street',
suite: 'Apt. 321',
city: 'Attenborough',
zipcode: '93187-4259',
geo: {
lat: '-37.9911',
lng: '82.0137',
},
},

So now that we have defined what our more advanced user object is going to look like, what are the ramifications for our User interface?

因此,既然我们已经定义了高级用户对象的外观,那么User界面的后果是什么?

export interface User {
id: number;
name: string;
username: string;
email: string;
address: Address | Address[];
phone: string;
website: string;
company: Company;
}

The | is a very important piece here called a union type in TypeScript. This is basically saying that the address property can either be one single Address object or an array with one or more Address objects. In our case, we could get by without using a union type and strictly require the address property to be an array of Address objects. But this solutions allows flexibility and would still work with the prior user JSON object provided from JSONPlaceholder.

| 这是一个非常重要的部分,在TypeScript中称为联合类型。 这基本上是说address属性可以是一个单个Address对象,也可以是具有一个或多个Address对象的数组。 在我们的例子中,我们可以不使用联合类型来实现,并且严格要求address属性是Address对象的数组。 但是此解决方案具有灵活性,并且仍可以与JSONPlaceholder提供的先前的用户JSON对象一起使用。

const logUserAddress = (userAddress: Address | Address[]) => {
if (Array.isArray(userAddress)) {
console.log(`The user has ${userAddress.length} addresses`);
for (const [index, address] of userAddress.entries()) {
console.log(`The user's address ${index + 1} is ${address.street} ${address.suite}`);
}
} else {
console.log(`The user's address is ${userAddress.street} ${userAddress.suite}`);
}
};const getUser = (user: User) => {
console.log(`The user's name is ${user.name}`);
console.log(`The user's phone number is ${user.phone}`);
logUserAddress(user.address);
};

After taking a look at the functions, this may look complicated, but it’s simpler than it looks. We do a simple check to determine if the userAddress is an array, and if so, we can loop through that array for the address information. Otherwise, the userAddress will be an object, and we can access the properties as we did previously.

看完函数后,这看起来很复杂,但是比看起来要简单。 我们进行简单的检查以确定userAddress是否为数组,如果是,则可以遍历该数组以获取地址信息。 否则, userAddress将是一个对象,我们可以像以前一样访问属性。

使用函数属性 (Using Function Properties)

So what if you need to add a function in an interface? No problem.

那么,如果您需要在接口中添加功能呢? 没问题。

{
id: 1,
name: 'Leanne Graham',
// ... removed to make it shorter / easier to read
company: {
name: 'Romaguera-Crona',
catchPhrase: 'Multi-layered client-server neural-net',
bs: 'harness real-time e-markets',
},
logCompany: (company) => {
console.log(company.name);
},
}

You will notice a new property here, named logCompany, and it is a function with the parameter of company. The logCompany function will log the name property of the company object provided.

您将在此处注意到一个名为logCompany的新属性,它是带有company.参数的函数company. logCompany函数将记录提供的company对象的name属性。

How does this affect the User interface?

这如何影响User界面?

export interface User {
id: number;
name: string;
username: string;
email: string;
address: Address | Address[];
phone: string;
website: string;
company: Company;
logCompany?: (company: Company) => void;
}

The User interface has the optional logCompany property that takes a parameter of company, which is the Company interface. This is another example of the benefit of breaking down the objects to their own interfaces. The void would be the return type of the function. In our case, we are not returning a value, as we logging to the console. If you were to return a value, say, of type string or boolean, etc., you would need to specify that return type in the interface.

User接口具有可选logCompany属性,可以取的参数company ,这是Company的接口。 这是将对象分解为自己的接口的好处的另一个示例。 void将是函数的返回类型。 在我们的例子中,当我们登录到控制台时,我们没有返回任何值。 如果要返回stringboolean等类型的boolean ,则需要在接口中指定该返回类型。

Taking a look at the getUser function, we can see that as the last line of the function we have user.logCompany?.(user.company);, which essentially states that if we have the the logCompany property, we need to execute it as a function with the parameter of user.company. This will succeed as user.company is of the definition specified in the Company interface.

看一下getUser函数,我们可以看到作为函数的最后一行,我们有user.logCompany?.(user.company); ,它基本上声明如果我们具有logCompany属性,则需要使用user.company参数将其作为函数执行。 如果user.company具有Company界面中指定的定义,则此操作将成功。

const getUser = (user: User) => {
log.result(`The user's name is ${user.name}`);
log.result(`The user's phone number is ${user.phone}`);
logUserAddress(user.address);
user.logCompany?.(user.company);
};

异步功能 (Asynchronous functions)

As well, you can absolutely use asynchronous functions as a property of an interface. As an example, if you were using a Promise for logCompany, the Promise would wrap the return type (in our case void) making the interface look like:

同样,您可以绝对使用异步函数作为接口的属性。 例如,如果您将Promise用于logCompany ,则Promise将包装返回类型(在我们的示例中为void)使接口看起来像:

logCompany?: (company: Company) => Promise<void>;

Then, of course, we would need to make the getUser function asynchronous by adding the async keyword. We would also need to add the await keyword prior to the user.logCompany?.(user.company); line.

然后,当然,我们需要通过添加async关键字使getUser函数异步。 我们还需要在user.logCompany?.(user.company);之前添加await关键字user.logCompany?.(user.company); 线。

const getUser = async (user: User) => {
log.result(`The user's name is ${user.name}`);
log.result(`The user's phone number is ${user.phone}`);
logUserAddress(user.address);
await user.logCompany?.(user.company);
};

结论和其他资源 (Conclusion and Additional Resources)

Thanks for making it this far. I really hope you found this article useful and that the examples improved your understanding of TypeScript interfaces.

感谢您到目前为止。 我真的希望您发现本文有用,并且这些示例可以增进您对TypeScript接口的理解。

Below I have included a GitHub gist with the full code we went over in this article. This can also be copied and used in the TypeScript Playground.

下面,我包含了GitHub要点,以及我们在本文中介绍的完整代码。 这也可以在TypeScript Playground中复制和使用。

If you want some additional resources for understanding TypeScript interfaces, I’d recommend taking a look at TypeScripts official docs. Another excellent resource is Udemy. I’m currently enrolled in the Understanding TypeScript — 2020 Edition and can safely say this is a great resource for all sorts of TypeScript knowledge, including interfaces.

如果您需要其他资源来了解TypeScript接口,建议您看一下TypeScripts官方文档。 另一个极好的资源是Udemy。 我目前已经参加了《理解TypeScript — 2020版》 ,可以放心地说,这是获取各种TypeScript知识(包括界面)的好资源。

I also have a GitHub repository with all my JavaScript and TypeScript tips and tricks. You can clone that repo, and after installing dependencies with npm install, you can then run npm run ts:interfaces. You can also modify the interfaces.ts to satistfy your desire to learn even more and have a local TypeScript playground.

我也有一个GitHub存储库,其中包含我所有JavaScript和TypeScript技巧。 您可以克隆该存储库,并在使用npm install安装依赖项之后,然后可以运行npm run ts:interfaces 。 您还可以修改interfaces.ts以满足更多学习需求并拥有本地TypeScript游乐场。

https://gist.github.com/tengel92/a54c0d55cb2b5f314ac55d55065486a0 https://gist.github.com/tengel92/a54c0d55cb2b5f314ac55d55065486a0

翻译自: https://medium.com/better-programming/a-comprehensive-guide-to-typescript-interfaces-16c5749fac2b

高德地图打字界面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值