docs: finish chapter object

This commit is contained in:
ruanyf
2023-07-18 11:22:24 +08:00
parent 739e3636b6
commit 98936e5abc
3 changed files with 39 additions and 37 deletions

View File

@@ -6,3 +6,4 @@
- tuple.md: 元组
- symbol.md: symbol 类型
- function.md: 函数
- object.md: 对象

View File

@@ -50,20 +50,20 @@ function add(x, y) {
return x + y;
}
add(1, [1, 2, 3]) // 正确
add(1, [1, 2, 3]) // 不报错
```
上面示例中,函数`add()`的参数变量`x``y`都没有足够的信息TypeScript 无法推断出它们的类型,就会认为这两个变量和函数返回值的类型都是`any`。以至于后面就不再对函数`add()`进行类型检查了,怎么用都可以。
这显然是很糟糕的情况,所以对于那些类型不明显的变量,一定要显式声明类型,防止被推断为`any`
TypeScript 提供了一个编译选项`--noImplicitAny`,打开该选项,只要推断出`any`类型就会报错。
TypeScript 提供了一个编译选项`noImplicitAny`,打开该选项,只要推断出`any`类型就会报错。
```bash
$ tsc --noImplicitAny app.ts
```
上面命令使用了`--noImplicitAny`编译选项进行编译,这时上面的函数`add()`就会报错。
上面命令使用了`noImplicitAny`编译选项进行编译,这时上面的函数`add()`就会报错。
### 污染问题
@@ -73,10 +73,10 @@ $ tsc --noImplicitAny app.ts
let x:any = 'hello';
let y:number;
y = x; // 正确
y = x; // 不报错
y * 123 // 正确
y.toFixed() // 正确
y * 123 // 不报错
y.toFixed() // 不报错
```
上面示例中,变量`x`的类型是`any`,实际的值是一个字符串。变量`y`的类型是`number`,表示这是一个数值变量,但是它被赋值为`x`,这时并不会报错。然后,变量`y`继续进行各种数值运算TypeScript 也检查不出错误,问题就这样留到运行时才会暴露。
@@ -207,9 +207,9 @@ function f():never {
throw new Error('Error');
}
let v1:number = f(); // 正确
let v2:string = f(); // 正确
let v3:string = f(); // 正确
let v1:number = f(); // 不报错
let v2:string = f(); // 不报错
let v3:string = f(); // 不报错
```
上面示例中,函数`f()`会抛错,所以返回值类型可以写成`never`,即不可能返回任何值。各种其他类型的变量都可以赋值为`f()`的运行结果(`never`类型)。

View File

@@ -7,9 +7,9 @@
对象类型的最简单声明方法,就是使用大括号表示对象,在大括号内部声明每个属性和方法的类型。
```typescript
const obj:{
const obj:{
x:number;
y:number;
y:number;
} = { x: 1, y: 1 };
```
@@ -36,9 +36,9 @@ type MyObj = {
一旦声明了类型,对象赋值时,就不能缺少指定的属性,也不能有多余的属性。
```typescript
type MyObj = {
type MyObj = {
x:number;
y:number;
y:number;
};
const o1:MyObj = { x: 1 }; // 报错
@@ -50,9 +50,9 @@ const o2:MyObj = { x: 1, y: 1, z: 1 }; // 报错
读写不存在的属性也会报错。
```typescript
const obj:{
const obj:{
x:number;
y:number;
y:number;
} = { x: 1, y: 1 };
console.log(obj.z); // 报错
@@ -83,13 +83,13 @@ const obj:{
add(x:number, y:number): number;
// 或者写成
// add: (x:number, y:number) => number;
} = {
x: 1,
y: 1,
} = {
x: 1,
y: 1,
add(x, y) {
return x + y;
}
};
}
};
```
上面示例中,对象`obj`有一个方法`add()`,需要定义它的参数类型和返回值类型。
@@ -110,9 +110,9 @@ type Name = User['name']; // string
```typescript
// 写法一
type MyObj = {
type MyObj = {
x:number;
y:number;
y:number;
};
const obj:MyObj = { x: 1, y: 1 };
@@ -123,7 +123,7 @@ interface MyObj {
y: number;
}
const obj:MyObj = { x: 1, y: 1 };
const obj:MyObj = { x: 1, y: 1 };
```
上面示例中,写法一是`type`命令的用法,写法二是`interface`命令的用法。`interface`命令的详细解释,以及与`type`命令的区别详见《Interface》一章。
@@ -148,9 +148,9 @@ const obj:MyInterface = { // 正确
如果某个属性是可选的(即可以忽略),需要在属性名后面加一个问号。
```typescript
const obj: {
const obj: {
x: number;
y?: number;
y?: number;
} = { x: 1 };
```
@@ -200,11 +200,11 @@ if (user.lastName !== undefined) {
}
```
上面示例中,`lastName`是可选属性,需要判断是否为`undefined`以后,才能使用。建议可以使用下面的写法。
上面示例中,`lastName`是可选属性,需要判断是否为`undefined`以后,才能使用。建议使用下面的写法。
```typescript
// 写法一
let firstName = (user.firstName === undefined)
let firstName = (user.firstName === undefined)
? 'Foo' : user.firstName;
let lastName = (user.lastName === undefined)
? 'Bar' : user.lastName;
@@ -286,7 +286,7 @@ interface Person {
name: string;
age: number;
}
interface ReadonlyPerson {
readonly name: string;
readonly age: number;
@@ -344,12 +344,12 @@ const obj:MyObj = {
foo: 'a',
bar: 'b',
baz: 'c',
};
};
```
上面示例中,类型`MyObj`的属性名类型就采用了表达式形式,写在方括号里面。`[property: string]``property`表示属性名,这个是可以随便起的,它的类型是`string`,即属性名类型为`string`。也就是说,不管这个对象有多少属性,只要属性名为字符串,且属性值也是字符串,就符合这个类型声明。
属性名(即上例的`property`)的类型有三种可能,除了上例的`string`,还有`number``symbol`
JavaScript 对象的属性名(即上例的`property`)的类型有三种可能,除了上例的`string`,还有`number``symbol`
```typescript
type T1 = {
@@ -430,7 +430,7 @@ const {id, name, price} = product;
const {id, name, price}:{
id: string;
name: string;
price: number
price: number
} = product;
```
@@ -520,7 +520,7 @@ function getSum(obj:myObj) {
}
```
上面示例中,函数`getSum()`要求传入参数的类型是`myObj`,但是实际上所有与`myObj`兼容的对象都可以传入。这会导致`const v = obj[n]`这一行报错,原因是`obj[n]`取出的属性值不一定是数值(`number`),使得变量`v`的类型`any`。如果不允许变量类型推断为`any`,代码就会报错。如果写成下面这样,就不会报错。
上面示例中,函数`getSum()`要求传入参数的类型是`myObj`,但是实际上所有与`myObj`兼容的对象都可以传入。这会导致`const v = obj[n]`这一行报错,原因是`obj[n]`取出的属性值不一定是数值(`number`),使得变量`v`的类型被推断为`any`。如果项目设置为不允许变量类型推断为`any`,代码就会报错。写成下面这样,就不会报错。
```typescript
type MyObj = {
@@ -569,7 +569,7 @@ const point:{
上面示例中,等号右边是一个变量,就不会触发严格字面量检查,从而不报错。
TypeScript 对字面量进行严格检查的目的,主要是防止拼写错误。一般来说,字面量大多数来自手写,容易出现拼写错误,或者误用 API。
TypeScript 对字面量进行严格检查的目的,主要是防止拼写错误。一般来说,字面量大多数来自手写,容易出现拼写错误,或者误用 API。
```typescript
type Options = {
@@ -603,7 +603,7 @@ const Obj:Options = myOptions;
```typescript
const Obj:Options = {
title: '我的网页',
darkmode: true,
darkmode: true,
} as Options;
```
@@ -638,7 +638,7 @@ computeDistance({x: 1, y: 2}); // 正确
上面示例中,对象字面量传入函数`computeDistance()`时,不能有多余的属性,否则就通不过严格字面量检查。
编译器选项`suppressExcessPropertyErrors`,可以`tsconfig.json`文件里面关闭多余属性检查
编译器选项`suppressExcessPropertyErrors`,可以关闭多余属性检查。下面是它在 tsconfig.json 文件里面的写法
```typescript
{
@@ -745,9 +745,9 @@ d = 'hello';
d = 2;
```
上面示例中,各类型的值(除了`null``undefined`)都可以赋值给空对象类型,跟`Object`类型的行为是一样的。
上面示例中,各类型的值(除了`null``undefined`)都可以赋值给空对象类型,跟`Object`类型的行为是一样的。
由于空对象是`Object`类型的简写,所以它不会有严格字面量检查,赋值时总是允许多余的属性,只是不能读取这些属性。
因为`Object`可以接受各种类型的值,而空对象是`Object`类型的简写,所以它不会有严格字面量检查,赋值时总是允许多余的属性,只是不能读取这些属性。
```typescript
interface Empty { }
@@ -769,3 +769,4 @@ const a:WithoutProperties = { prop: 1 };
```
上面的示例中,`[key: string]: never`表示字符串属性名是不存在的,因此其他对象进行赋值时就会报错。