- Published on
TypeScript - 对象
- Authors
- Name
- Deng Hua
目录
对象
Objects can be typed by declaring what the object should look like in the annotation. Accessing a property that isn't defined or performing operations without keeping types in mind will throw errors!
在typescript中,我们可以创建注释,用于描述对象的属性。
// printName函数接受一个对象作为参数
const printName = (person: { first: string, last: string }): void => { }
printName({ first: 'john', last: 'lennon' });
在参数对象内,我们使用类型注释为形参person
提供了类型约束。
如果把鼠标移到形参person上,会发现TS提示我们person的类型。
(parameter) person: {
first: string;
last: string;
}
对象字面量
对象字面量的类型
let coordinate: { x: number, y: number } = { x: 34, y: 2 }
与变量的基本类型注释的语法一致,在变量后添加冒号:
与类型注释即可。
函数返回值为对象
下例中,我们为randomCoordinate
函数指定了一个返回值为对象类型注释
function randomCoordinate(): { x: number, y: number } {
return {} // ❌ 类型“{}”缺少类型“{ x: number; y: number; }”中的以下属性: x, y
}
如果此时返回值类型与类型注释不一致,TS检查便会报错。
function randomCoordinate(): { x: number, y: number } {
return { x: Math.random(), y: Math.random() }
}
剩余属性
const printName = (person: { first: string, last: string }): void => { }
在这个例子中,为函数提供了没有在类型注释内的其他参数,TS会如何反应?
- 意味着参数对象的第一个参数必须为
first
,最后一个必须为last
,不允许在提供其他参数? - 或是必须有第一个参数
first
和第二个参数last
,其他都是可选的?
结果我们看到了TS的报错:
const printName = (person: { first: string, last: string }): void => { }
printName({
first: 'john',
last: 'lennon',
age: 10, // ❌ 对象字面量只能指定已知属性,并且“age”不在类型“{ first: string; last: string; }”中
});
但是让我们换一种写法
const printName = (person: { first: string, last: string }): void => { }
const john = { first: 'john', last: 'lennon', age: 10 }
printName(john); // ✅
我们神奇的发现,TS的报错消失了。
比较这两种方式的对象定义
printName({ first: 'john', last: 'lennon', age: 10, });
const john = { first: 'john', last: 'lennon', age: 10 }
printName(john)
第一种字面量定义,会使得TS使用严格的类型检查,对象字面量只能指定已知属性。这是有道理的并且是预期的,因为我们的类型person
不包含该age
属性。
但是,在某些情况下,当对象中有多余的属性时,Typescript 将保持沉默,这便是第二种情况。
在这种情况下,Typescript不会检查多余的属性,因为类型person是变量john
推断的类型的子集,该变量推断包括person
加age
中的所有属性。这在TS中被称为类型结构。
If it walks like a duck and it quacks like a duck, then it must be a duck
换句话说,变量john
拥有person
类型的一切特征。
参考文章: 函数类型兼容性 从类型兼容开始,认识 TypeScript
Type Alias
Instead of writing out object types in an annotation, we can declare them separaretly in a type alias, which is simply the desired shape of the object. This allows us to make our code more readable and even reuse the types elsewhere in our code.
这是一种为类型命名的方法
function doublePoint(point: { x: number, y: number }): { x: number, y: number } {
return { x: point.x * 2, y: point.y * 2 }
}
在这个例子中,类型point
与返回值类型拥有一致的机构,我们可以使用type
关键字定义。
type Point = {
x: number;
y: number;
}
function doublePoint(point: Point): Point {
return { x: point.x * 2, y: point.y * 2 }
}
Nested Objects
对嵌套对象的类型注释也十分简单
const describePerson = (person: {
name: string;
age: number;
parents: {
mom: string;
dad: string;
}
}) => {
return `
Person: ${person.name},
Age: ${person.age},
parents: ${person.parents.mom} , ${person.parents.dad}
`
}
describePerson({ name: 'john', age: 10, parents: { mom: 'kim', dad: 'steve' } })
Optional Properties
可选属性的使用
type Point = {
x: number;
y: number;
z?:number;
}
const myPoint: Point = { x: 1, y: 3 } // ✅
ReadOnly Modifer
要使属性只读,在属性前添加readonly
关键字即可。
type User = {
readonly id: number;
name: string;
}
const user: User = { id: 100, name: 'john' }
user.id = 1; // 无法为“id”赋值,因为它是只读属性。
只读属性只允许作为右值使用
交叉类型
使用关键字&
即可对两个类型作为交叉类型使用
type Circle = {
radius: number;
}
type Colorful = {
color: string;
}
type ColorFulCircle = Circle & Colorful;
可以从集合的角度去理解交叉类型
此时对于ColorFulCircle
类型,它的类型即为Circle
和Colorful
的交集。
type Circle = {
radius: number;
}
type Colorful = {
color: string;
}
type ColorFulCircle = Circle & Colorful;
const happyFace: ColorFulCircle = {
radius: 4,// ❌ 不能将类型“{ radius: number; }”分配给类型“ColorFulCircle”。 类型 "{ radius: number; }" 中缺少属性 "color",但类型 "Colorful" 中需要该属性。
}
由于ColorFulCircle
类型中必须含有radius
和color
属性,缺少相关属性,TS便会报错。
当然,也可以拓展交叉类型:
type Cat = {
numLives: number
}
type Dog = {
breed: string
}
type CatDog = Cat & Dog & { age: number }
const christy: CatDog = {
numLives: 5,
breed: "Husky",
age: 9
}