版权声明
- 本文原创作者:谷哥的小弟
- 作者博客地址:http://blog.csdn.net/lfdfhl

TypeScript对象类型概述
对象用于保存一组相关数据,例如一个用户、一个学生、一个商品或一条订单记录。与单个字符串、数字、布尔值不同,对象通常由多个属性组成,每个属性都表示这组数据中的一个具体字段。在 JavaScript 中,对象的属性添加和修改比较自由,但这种自由也可能带来问题。例如,一个商品对象中的价格本来应该是数字,如果后续被错误地改成字符串,就可能影响计算、排序或页面展示。
TypeScript 的对象类型可以明确规定对象应该包含哪些属性,以及每个属性应该保存什么类型的数据。对象类型通常写在变量名后面,用一对花括号描述对象结构,例如 { username: string; age: number }。这表示对象必须包含 username 和 age 两个属性,其中 username 必须是字符串,age 必须是数字。对象数据本身则写在等号右边,例如 { username: "jack", age: 18 }。初学时要注意区分:等号左边描述类型结构,等号右边才是实际数据。
使用对象类型时,属性名和属性类型都要对应。对象类型中声明了什么属性,对象数据中就应该按照对应名称提供属性。如果类型中要求的是 name,实际对象却写成 username,TypeScript 会认为对象结构不匹配。同样,如果类型中规定 price 是 number,实际数据却写成 "199",也会出现类型错误。带引号的 "199" 是字符串,不是数字。
对象类型还会检查属性是否完整。如果某个属性在类型中被定义为普通属性,那么对象数据中通常必须提供这个属性。缺少必需属性会导致类型错误。相反,如果直接给一个带有对象类型标注的变量赋值,对象中多出类型里没有声明的属性,也可能出现错误。对于初学者来说,可以先理解为:对象类型中声明了哪些属性,对象数据就按照这个结构来写,既不要少写必需属性,也不要随意增加未声明属性。
有些对象属性并不是每次都一定存在,这时可以使用可选属性。可选属性的写法是在属性名后面加 ?,例如 address?: string。它表示对象可以没有 address 属性;如果提供了 address,它的值必须是字符串。可选属性适合描述接口数据、用户资料、商品描述等不一定完整的数据字段。需要注意的是,可选属性如果没有提供,读取时可能得到 undefined,后续使用时要考虑这种情况。
对象类型也可以和数组结合使用,形成对象数组。对象数组用于保存一组结构相同的对象,例如学生列表、商品列表、用户列表等。写法通常类似 { name: string; age: number }[],表示数组中的每一项都必须是具有 name 和 age 属性的对象。对象数组在 Vue3 中非常常见,后续学习列表渲染、表格展示和接口返回数据时,经常会处理这类结构。
对象类型还经常用于函数参数。当一个函数接收一个对象作为参数时,可以直接为这个参数标注对象类型,明确调用函数时必须传入怎样的对象。例如,打印用户信息的函数可以要求参数必须包含 username 和 age。这样一来,如果调用函数时缺少属性,或者属性类型不正确,TypeScript 就能提前提示问题。
如果对象属性较少,可以直接在变量或函数参数中写对象类型。但当对象结构变复杂,或者同一种对象结构需要多次使用时,直接书写对象类型就会显得冗长。后续学习类型别名和接口后,可以把对象结构单独提取出来,让代码更清晰。掌握对象类型后,再学习 Vue3 中的数据对象、列表数据、组件参数和接口返回结果时,会更容易理解这些数据结构的含义。
案例源码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TypeScript 对象类型</title>
</head>
<body>
<h1>TypeScript 对象类型</h1>
<p>
本节学习 TypeScript 中对象类型的基本写法。
对象用于保存一组相关数据,例如一个学生、一个用户、一个商品等。
</p>
<p>
在 JavaScript 中,对象的属性可以比较自由地添加和修改。
在 TypeScript 中,可以明确规定对象应该有哪些属性,
以及每个属性应该保存什么类型的数据。
</p>
<p>
说明:本节中的代码是 TypeScript 代码,浏览器不能直接运行。
当前阶段建议使用 TypeScript 官方在线工具
<a href="https://www.typescriptlang.org/play/" target="_blank">TypeScript Playground</a>
测试代码。
</p>
<hr>
<h2>一、为什么需要对象类型</h2>
<p>
在 JavaScript 中,对象常用于保存一组相关数据。
</p>
<pre><code>let student = {
name: "张三",
age: 18
};</code></pre>
<p>
这个对象表示一个学生。
其中,<code>name</code> 表示姓名,<code>age</code> 表示年龄。
</p>
<p>
如果后续代码中不小心把年龄改成字符串,JavaScript 本身不会在编写阶段提示错误。
</p>
<pre><code>student.age = "十八";</code></pre>
<p>
这可能导致后续代码出现问题。
例如,原本想对年龄进行数字运算,但年龄却变成了字符串。
</p>
<p>
TypeScript 可以通过对象类型规定对象属性的类型。
</p>
<pre><code>let student: { name: string; age: number } = {
name: "张三",
age: 18
};
student.age = 20; // 正确
student.age = "二十"; // 错误:age 应该是 number</code></pre>
<p>
这就是对象类型的作用:
<strong>规定对象应该有哪些属性,并规定每个属性的数据类型。</strong>
</p>
<hr>
<h2>二、对象类型的基本写法</h2>
<p>
对象类型的基本格式如下:
</p>
<pre><code>let 变量名: { 属性名: 类型; 属性名: 类型 } = {
属性名: 值,
属性名: 值
};</code></pre>
<p>
例如:
</p>
<pre><code>let user: { username: string; age: number } = {
username: "jack",
age: 18
};</code></pre>
<p>
这段代码中:
</p>
<ol>
<li><code>user</code> 是变量名。</li>
<li><code>{ username: string; age: number }</code> 是对象类型。</li>
<li><code>username: string</code> 表示对象必须有 <code>username</code> 属性,并且值必须是字符串。</li>
<li><code>age: number</code> 表示对象必须有 <code>age</code> 属性,并且值必须是数字。</li>
</ol>
<p>
注意:
等号左边的 <code>username: string</code> 是类型标注;
等号右边的 <code>username: "jack"</code> 才是真正的数据。
</p>
<pre><code>let user: { username: string; age: number } = {
username: "jack",
age: 18
};</code></pre>
<p>
可以这样理解:
</p>
<pre><code>{ username: string; age: number } // 规定对象结构
{ username: "jack", age: 18 } // 提供对象数据</code></pre>
<hr>
<h2>三、对象属性名必须对应</h2>
<p>
初学者容易疑惑:
对象类型中的属性名是不是可以随便写?
</p>
<p>
答案是:
<strong>不能随便写。</strong>
对象类型中的属性名,必须和对象数据中的属性名对应。
</p>
<pre><code>let student: { name: string; age: number } = {
name: "张三",
age: 18
};</code></pre>
<p>
上面代码是正确的,因为类型中声明了 <code>name</code> 和 <code>age</code>,
对象数据中也提供了 <code>name</code> 和 <code>age</code>。
</p>
<p>
下面这种写法是错误的:
</p>
<pre><code>let student: { name: string; age: number } = {
username: "张三",
age: 18
};</code></pre>
<p>
错误原因:
类型中要求对象必须有 <code>name</code> 属性,
但是实际对象中写的是 <code>username</code> 属性。
</p>
<p>
如果想使用 <code>username</code> 作为属性名,
类型中也应该写成 <code>username</code>。
</p>
<pre><code>let student: { username: string; age: number } = {
username: "张三",
age: 18
};</code></pre>
<p>
也就是说:
<strong>类型中的属性名,要和对象中的属性名保持一致。</strong>
</p>
<hr>
<h2>四、对象属性类型必须对应</h2>
<p>
除了属性名要对应,属性值的类型也要对应。
</p>
<pre><code>let product: { name: string; price: number } = {
name: "键盘",
price: 199
};</code></pre>
<p>
上面代码中:
</p>
<ol>
<li><code>name</code> 应该是字符串。</li>
<li><code>price</code> 应该是数字。</li>
</ol>
<p>
所以下面这种写法是错误的:
</p>
<pre><code>let product: { name: string; price: number } = {
name: "键盘",
price: "199"
};</code></pre>
<p>
错误原因:
<code>price</code> 被标注为 <code>number</code>,
但是 <code>"199"</code> 是字符串。
</p>
<p>
正确写法:
</p>
<pre><code>let product: { name: string; price: number } = {
name: "键盘",
price: 199
};</code></pre>
<p>
记住:
<strong>属性名要对,属性值的类型也要对。</strong>
</p>
<hr>
<h2>五、对象缺少属性会报错</h2>
<p>
如果对象类型中规定了某个属性,
那么对象数据中通常必须提供这个属性。
</p>
<pre><code>let user: { username: string; age: number } = {
username: "jack",
age: 18
};</code></pre>
<p>
上面代码是正确的,因为对象同时提供了 <code>username</code> 和 <code>age</code>。
</p>
<p>
下面这种写法是错误的:
</p>
<pre><code>let user: { username: string; age: number } = {
username: "jack"
};</code></pre>
<p>
错误原因:
类型中要求对象必须有 <code>age</code> 属性,
但是实际对象中缺少了 <code>age</code>。
</p>
<p>
正确写法:
</p>
<pre><code>let user: { username: string; age: number } = {
username: "jack",
age: 18
};</code></pre>
<hr>
<h2>六、对象多出属性也可能报错</h2>
<p>
如果直接给一个带类型标注的对象变量赋值,
对象中多写了类型中没有声明的属性,也可能报错。
</p>
<pre><code>let user: { username: string; age: number } = {
username: "jack",
age: 18,
address: "北京"
};</code></pre>
<p>
错误原因:
类型中只声明了 <code>username</code> 和 <code>age</code>,
但是对象数据中多出了 <code>address</code>。
</p>
<p>
如果确实需要 <code>address</code> 属性,
就应该在类型中声明它。
</p>
<pre><code>let user: { username: string; age: number; address: string } = {
username: "jack",
age: 18,
address: "北京"
};</code></pre>
<p>
当前阶段可以先记住:
<strong>对象类型中声明了哪些属性,对象数据就按照这个结构来写。</strong>
</p>
<hr>
<h2>七、可选属性</h2>
<p>
有些属性不是必须存在的。
这种属性可以定义为可选属性。
</p>
<p>
可选属性的写法是在属性名后面加 <code>?</code>。
</p>
<pre><code>let user: { username: string; age: number; address?: string } = {
username: "jack",
age: 18
};</code></pre>
<p>
这里的 <code>address?: string</code> 表示:
<code>address</code> 属性可以有,也可以没有。
如果有,必须是字符串。
</p>
<p>
下面两种写法都正确:
</p>
<pre><code>let user1: { username: string; age: number; address?: string } = {
username: "jack",
age: 18
};
let user2: { username: string; age: number; address?: string } = {
username: "lucy",
age: 20,
address: "上海"
};</code></pre>
<p>
但是,如果提供了 <code>address</code>,它的值仍然必须是字符串。
</p>
<pre><code>let user: { username: string; age: number; address?: string } = {
username: "jack",
age: 18,
address: 100
};</code></pre>
<p>
上面代码是错误的。
因为 <code>address</code> 如果存在,就应该是字符串。
</p>
<hr>
<h2>八、对象数组</h2>
<p>
在前端开发中,经常会遇到对象数组。
例如,一个学生列表就是由多个学生对象组成的数组。
</p>
<pre><code>let students: { name: string; age: number }[] = [
{ name: "张三", age: 18 },
{ name: "李四", age: 19 },
{ name: "王五", age: 20 }
];</code></pre>
<p>
这段代码中:
</p>
<ol>
<li><code>{ name: string; age: number }</code> 表示单个学生对象的类型。</li>
<li><code>[]</code> 表示这是一个数组。</li>
<li><code>{ name: string; age: number }[]</code> 表示数组中的每一项都必须是这种学生对象。</li>
</ol>
<p>
如果数组中某个对象的属性类型不正确,就会报错。
</p>
<pre><code>let students: { name: string; age: number }[] = [
{ name: "张三", age: 18 },
{ name: "李四", age: "19" }
];</code></pre>
<p>
错误原因:
第二个学生对象中的 <code>age</code> 应该是数字,
但是写成了字符串 <code>"19"</code>。
</p>
<p>
对象数组在 Vue3 中非常常见。
例如,后续使用 <code>v-for</code> 渲染列表时,
经常会处理类似的数据。
</p>
<hr>
<h2>九、函数参数中的对象类型</h2>
<p>
对象类型也经常用于函数参数。
</p>
<pre><code>function printUser(user: { username: string; age: number }): void {
console.log("用户名:" + user.username);
console.log("年龄:" + user.age);
}
printUser({
username: "jack",
age: 18
});</code></pre>
<p>
这段代码中:
</p>
<ol>
<li><code>user</code> 是函数参数。</li>
<li><code>{ username: string; age: number }</code> 规定了参数对象的结构。</li>
<li>调用函数时,传入的对象必须包含 <code>username</code> 和 <code>age</code>。</li>
</ol>
<p>
下面这种调用是错误的:
</p>
<pre><code>printUser({
username: "jack"
});</code></pre>
<p>
错误原因:
参数对象缺少 <code>age</code> 属性。
</p>
<p>
下面这种调用也是错误的:
</p>
<pre><code>printUser({
username: "jack",
age: "18"
});</code></pre>
<p>
错误原因:
<code>age</code> 应该是数字,但传入了字符串。
</p>
<hr>
<h2>十、对象类型写法较长时的问题</h2>
<p>
如果对象属性比较少,直接写对象类型还可以接受。
</p>
<pre><code>let user: { username: string; age: number } = {
username: "jack",
age: 18
};</code></pre>
<p>
但是,如果对象属性变多,类型写法就会变得很长。
</p>
<pre><code>let user: { username: string; age: number; address: string; isLogin: boolean } = {
username: "jack",
age: 18,
address: "北京",
isLogin: true
};</code></pre>
<p>
这种写法可以运行,但阅读起来不够方便。
后面学习 <strong>类型别名</strong> 或 <strong>接口</strong> 后,
可以把对象类型单独提取出来,让代码更清晰。
</p>
<p>
当前阶段先掌握对象类型的基本写法即可。
</p>
<hr>
<h2>十一、完整小示例</h2>
<p>
下面通过一个商品列表案例,综合演示对象类型和对象数组。
</p>
<pre><code>// 单个商品对象
let product: { name: string; price: number; inStock: boolean } = {
name: "键盘",
price: 199,
inStock: true
};
// 商品数组
let productList: { name: string; price: number; inStock: boolean }[] = [
{ name: "键盘", price: 199, inStock: true },
{ name: "鼠标", price: 99, inStock: true },
{ name: "显示器", price: 899, inStock: false }
];
// 打印单个商品信息
function printProduct(item: { name: string; price: number; inStock: boolean }): void {
console.log("商品名称:" + item.name);
console.log("商品价格:" + item.price);
console.log("是否有库存:" + item.inStock);
}
// 遍历商品数组
productList.forEach(function (item) {
printProduct(item);
});
// 正确修改
product.price = 219;
// 错误示例
// product.price = "219";
// product.inStock = "有货";
// productList.push({ name: "音箱", price: "299", inStock: true });</code></pre>
<p>
这个案例中:
</p>
<ol>
<li><code>product</code> 是一个商品对象。</li>
<li><code>productList</code> 是商品对象数组。</li>
<li><code>printProduct</code> 函数接收一个商品对象作为参数。</li>
<li>商品名称必须是字符串。</li>
<li>商品价格必须是数字。</li>
<li>是否有库存必须是布尔值。</li>
</ol>
<p>
对象类型可以让数据结构更明确,
也能帮助我们在写代码时提前发现属性名或属性类型错误。
</p>
<hr>
<h2>十二、本节总结</h2>
<p>
本节学习了 TypeScript 对象类型。
</p>
<ol>
<li>对象用于保存一组相关数据。</li>
<li>对象类型可以规定对象应该有哪些属性。</li>
<li>对象类型可以规定每个属性的数据类型。</li>
<li>对象类型中的属性名要和对象数据中的属性名对应。</li>
<li>对象属性值的类型要和类型标注保持一致。</li>
<li>对象缺少必需属性会报错。</li>
<li>对象直接赋值时,多出未声明属性也可能报错。</li>
<li>属性名后面加 <code>?</code> 可以表示可选属性。</li>
<li>对象数组用于保存一组结构相同的对象。</li>
<li>对象类型可以用于函数参数。</li>
<li>对象类型写法较长时,后续可以使用类型别名或接口进行简化。</li>
</ol>
</body>
</html>