- It is possible to support both types of indexers...
- It is possible to support both types of indexers, but the type returned from a numeric indexer must be a subtype of the type returned from the string indexer. This is because when indexing with a number
, JavaScript will actually convert that to a string
before indexing into an object. That means that indexing with 100
(a number
) is the same thing as indexing with "100"
(a string
), so the two need to be consistent.
+ 它是可以同时支持两种类型的索引器的...
+ 它是可以同时支持两种类型的索引器的,但是数字索引器返回的类型必须是字符串索引器返回类型的子类型。这是因为在使用 number
进行索引时,JavaScript 实际上会将其转换为 string
,然后再对对象进行索引。这意味着使用 100
(一个 `number`)进行索引与使用 "100"
(一个 string
)进行索引是一样的,所以两者需要保持一致。
```ts twoslash
// @errors: 2413
@@ -288,7 +277,7 @@ interface Dog extends Animal {
breed: string;
}
-// Error: indexing with a numeric string might get you a completely separate type of Animal!
+// 错误:使用数字字符串进行索引可能会得到一个完全不同类型的 Animal!
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog;
@@ -297,9 +286,7 @@ interface NotOkay {
-While string index signatures are a powerful way to describe the "dictionary" pattern, they also enforce that all properties match their return type.
-This is because a string index declares that `obj.property` is also available as `obj["property"]`.
-In the following example, `name`'s type does not match the string index's type, and the type checker gives an error:
+虽然字符串索引签名是描述“字典”模式的强大方式,但它也强制要求所有属性与它们的返回类型匹配。这是因为字符串索引声明了 `obj.property` 也可以使用 `obj["property"]` 访问。在下面的例子中,`name` 的类型与字符串索引的类型不匹配,类型检查器会报错:
```ts twoslash
// @errors: 2411
@@ -307,22 +294,22 @@ In the following example, `name`'s type does not match the string index's type,
interface NumberDictionary {
[index: string]: number;
- length: number; // ok
+ length: number; // 可行
name: string;
}
```
-However, properties of different types are acceptable if the index signature is a union of the property types:
+然而,如果索引签名是属性类型的联合类型,不同类型的属性是可以接受的:
```ts twoslash
interface NumberOrStringDictionary {
[index: string]: number | string;
- length: number; // ok, length is a number
- name: string; // ok, name is a string
+ length: number; // 可行,length 是一个数字
+ name: string; // 可行,name 是一个字符串
}
```
-Finally, you can make index signatures `readonly` in order to prevent assignment to their indices:
+最后,你可以将索引签名设置为 `readonly`,以防止对索引项进行赋值:
```ts twoslash
declare function getReadOnlyStringArray(): ReadonlyStringArray;
@@ -336,12 +323,11 @@ let myArray: ReadonlyStringArray = getReadOnlyStringArray();
myArray[2] = "Mallory";
```
-You can't set `myArray[2]` because the index signature is `readonly`.
+你不能设置 `myArray[2]`,因为索引签名是 `readonly` 的。
-## Excess Property Checks
+## 多余属性检查
-Where and how an object is assigned a type can make a difference in the type system.
-One of the key examples of this is in excess property checking, which validates the object more thoroughly when it is created and assigned to an object type during creation.
+对象被赋予类型的位置和方式会对类型系统产生影响。其中一个关键例子是多余属性检查(excess property checking),它在对象创建并赋值给对象类型时更加彻底地验证对象。
```ts twoslash
// @errors: 2345 2739
@@ -360,14 +346,11 @@ function createSquare(config: SquareConfig): { color: string; area: number } {
let mySquare = createSquare({ colour: "red", width: 100 });
```
-Notice the given argument to `createSquare` is spelled _`colour`_ instead of `color`.
-In plain JavaScript, this sort of thing fails silently.
+注意,传递给 `createSquare` 的参数中将 `color` 拼写为 _`colour`_ 而不是 `color`。在普通的 JavaScript 中,这种情况会悄无声息地失败。
-You could argue that this program is correctly typed, since the `width` properties are compatible, there's no `color` property present, and the extra `colour` property is insignificant.
+你可以认为这个程序是正确类型化的,因为 `width` 属性是兼容的,没有 `color` 属性存在,并且额外的 `colour` 属性是无关紧要的。
-However, TypeScript takes the stance that there's probably a bug in this code.
-Object literals get special treatment and undergo _excess property checking_ when assigning them to other variables, or passing them as arguments.
-If an object literal has any properties that the "target type" doesn't have, you'll get an error:
+然而,TypeScript 认为这段代码可能存在 bug。对象字面量在赋值给其他变量或作为实参传递时会经历_额外的属性检查_。如果对象字面量具有任何目标类型不具备的属性,就会产生错误:
```ts twoslash
// @errors: 2345 2739
@@ -386,8 +369,7 @@ function createSquare(config: SquareConfig): { color: string; area: number } {
let mySquare = createSquare({ colour: "red", width: 100 });
```
-Getting around these checks is actually really simple.
-The easiest method is to just use a type assertion:
+绕过这些检查实际上非常简单。最简单的方法是使用类型断言:
```ts twoslash
// @errors: 2345 2739
@@ -406,8 +388,7 @@ function createSquare(config: SquareConfig): { color: string; area: number } {
let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
```
-However, a better approach might be to add a string index signature if you're sure that the object can have some extra properties that are used in some special way.
-If `SquareConfig` can have `color` and `width` properties with the above types, but could _also_ have any number of other properties, then we could define it like so:
+然而,如果你确定该对象可以具有一些额外的属性,并且这些属性在某种特殊方式下使用,一种更好的方法是在对象上添加字符串索引签名。如果 `SquareConfig` 可以具有上述类型的 `color` 和 `width` 属性,但_还_可以具有任意数量的其他属性,那么我们可以这样定义它:
```ts twoslash
interface SquareConfig {
@@ -417,10 +398,9 @@ interface SquareConfig {
}
```
-Here we're saying that `SquareConfig` can have any number of properties, and as long as they aren't `color` or `width`, their types don't matter.
+在这里,我们表示 `SquareConfig` 可以具有任意数量的属性,只要它们不是 `color` 或 `width`,它们的类型就无关紧要。
-One final way to get around these checks, which might be a bit surprising, is to assign the object to another variable:
-Since assigning `squareOptions` won't undergo excess property checks, the compiler won't give you an error:
+最后一种绕过这些检查的方式可能有点令人惊讶,那就是将对象赋值给另一个变量:由于对 `squareOptions` 进行赋值不会进行多余属性检查,编译器不会报错:
```ts twoslash
interface SquareConfig {
@@ -440,8 +420,7 @@ let squareOptions = { colour: "red", width: 100 };
let mySquare = createSquare(squareOptions);
```
-The above workaround will work as long as you have a common property between `squareOptions` and `SquareConfig`.
-In this example, it was the property `width`. It will however, fail if the variable does not have any common object property. For example:
+上述解决方法只适用于 `squareOptions` 和 `SquareConfig` 之间存在公共属性的情况。在这个例子中,公共属性是 `width`。然而,如果变量没有任何公共对象属性,这种解决方法将失败。例如:
```ts twoslash
// @errors: 2559
@@ -461,16 +440,13 @@ let squareOptions = { colour: "red" };
let mySquare = createSquare(squareOptions);
```
-Keep in mind that for simple code like above, you probably shouldn't be trying to "get around" these checks.
-For more complex object literals that have methods and hold state, you might need to keep these techniques in mind, but a majority of excess property errors are actually bugs.
+请记住,对于上述简单的代码,你最好不应该试图绕过这些检查。对于具有方法和状态的更复杂的对象字面量,你可能需要牢记这些技巧,但是绝大多数多余属性错误实际上是 bug。
-That means if you're running into excess property checking problems for something like option bags, you might need to revise some of your type declarations.
-In this instance, if it's okay to pass an object with both a `color` or `colour` property to `createSquare`, you should fix up the definition of `SquareConfig` to reflect that.
+这意味着,如果你在处理诸如选项包(option bags)之类的问题时遇到多余属性检查问题,你可能需要重新检查一些类型声明。在这种情况下,如果将同时具有 `color` 或 `colour` 属性的对象传递给 `createSquare` 是允许的,那么你应该修正 `SquareConfig` 的定义以反映这一点。
-## Extending Types
+## 拓展类型
-It's pretty common to have types that might be more specific versions of other types.
-For example, we might have a `BasicAddress` type that describes the fields necessary for sending letters and packages in the U.S.
+在类型系统中,有时候会存在一些更具体版本的类型。例如,我们可能有一个 `BasicAddress` 类型,用于描述在美国发送信函和包裹所需的字段。
```ts twoslash
interface BasicAddress {
@@ -482,8 +458,7 @@ interface BasicAddress {
}
```
-In some situations that's enough, but addresses often have a unit number associated with them if the building at an address has multiple units.
-We can then describe an `AddressWithUnit`.
+在某些情况下,这已经足够了,但是地址经常会有一个单元号与之关联,比如某个地址对应的建筑物有多个单元。我们可以描述 `AddressWithUnit` 类型。
```ts twoslash
@@ -498,8 +473,7 @@ interface AddressWithUnit {
}
```
-This does the job, but the downside here is that we had to repeat all the other fields from `BasicAddress` when our changes were purely additive.
-Instead, we can extend the original `BasicAddress` type and just add the new fields that are unique to `AddressWithUnit`.
+这样做是可以的,但是这里的缺点是,我们不得不在我们的更改中重复所有其他来自 `BasicAddress` 的字段,然而我们想要做的更改只是简单地添加。相反,我们可以扩展原始的 `BasicAddress` 类型来达到同样的效果,这样只需添加唯一属于 `AddressWithUnit` 的新字段就可以了。
```ts twoslash
interface BasicAddress {
@@ -515,11 +489,9 @@ interface AddressWithUnit extends BasicAddress {
}
```
-The `extends` keyword on an `interface` allows us to effectively copy members from other named types, and add whatever new members we want.
-This can be useful for cutting down the amount of type declaration boilerplate we have to write, and for signaling intent that several different declarations of the same property might be related.
-For example, `AddressWithUnit` didn't need to repeat the `street` property, and because `street` originates from `BasicAddress`, a reader will know that those two types are related in some way.
+在 `interface` 上使用 `extends` 关键字可以让我们有效地复制其他命名类型的成员,并添加任何我们想要的新成员。这可以减少我们必须编写的类型声明的样板代码量,并且可以表明多个对同一属性的不同声明可能相关联。例如,`AddressWithUnit` 不需要重复 `street` 属性,并且因为 `street` 来源于 `BasicAddress`,读者会知道这两个类型在某种程度上是相关的。
-`interface`s can also extend from multiple types.
+`interface` 也可以从多个类型进行扩展。
```ts twoslash
interface Colorful {
@@ -538,12 +510,11 @@ const cc: ColorfulCircle = {
};
```
-## Intersection Types
+## 交叉类型
-`interface`s allowed us to build up new types from other types by extending them.
-TypeScript provides another construct called _intersection types_ that is mainly used to combine existing object types.
+在 TypeScript 中,除了使用 `interface` 来扩展已有类型外,还提供了另一种构造方式,称为_交叉类型(intersection types)_,主要用于组合现有的对象类型。
-An intersection type is defined using the `&` operator.
+交叉类型使用 `&` 运算符进行定义。
```ts twoslash
interface Colorful {
@@ -556,7 +527,7 @@ interface Circle {
type ColorfulCircle = Colorful & Circle;
```
-Here, we've intersected `Colorful` and `Circle` to produce a new type that has all the members of `Colorful` _and_ `Circle`.
+在这个例子中,我们对 `Colorful` 和 `Circle` 进行了交叉,生成了新类型,该类型具有 `Colorful` _和_ `Circle` 的所有成员。
```ts twoslash
// @errors: 2345
@@ -568,31 +539,29 @@ interface Circle {
}
// ---cut---
function draw(circle: Colorful & Circle) {
- console.log(`Color was ${circle.color}`);
- console.log(`Radius was ${circle.radius}`);
+ console.log(`颜色是:${circle.color}`);
+ console.log(`半径是:${circle.radius}`);
}
-// okay
-draw({ color: "blue", radius: 42 });
+// 正常
+draw({ color: "蓝", radius: 42 });
-// oops
-draw({ color: "red", raidus: 42 });
+// 错误
+draw({ color: "红", raidus: 42 });
```
-## Interfaces vs. Intersections
+## 接口 vs. 交叉类型
-We just looked at two ways to combine types which are similar, but are actually subtly different.
-With interfaces, we could use an `extends` clause to extend from other types, and we were able to do something similar with intersections and name the result with a type alias.
-The principal difference between the two is how conflicts are handled, and that difference is typically one of the main reasons why you'd pick one over the other between an interface and a type alias of an intersection type.
+我们刚刚讨论了两种将相似但实际上略有不同的类型组合在一起的方法。使用接口,我们可以使用 `extends` 子句从其他类型进行扩展,而交叉类型后给结果起类型别名也与之相似,并且我们可以。两者之间的主要区别在于如何处理冲突,而这种区别通常是你选择接口还是交叉类型的主要依据之一。
-## Generic Object Types
+## 泛型对象类型
-Let's imagine a `Box` type that can contain any value - `string`s, `number`s, `Giraffe`s, whatever.
+让我们想象 `Box` 类型,它可以包含任何值——`string` 值、`number` 值、`Giraffe` 值,或者其他任何类型的值。
```ts twoslash
interface Box {
@@ -600,9 +569,9 @@ interface Box {
}
```
-Right now, the `contents` property is typed as `any`, which works, but can lead to accidents down the line.
+目前,`contents` 属性的类型为 `any`,这样也不是不能工作,但可能会在后续操作中导致错误。
-We could instead use `unknown`, but that would mean that in cases where we already know the type of `contents`, we'd need to do precautionary checks, or use error-prone type assertions.
+我们可以使用 `unknown`,但这意味着在我们已经知道 `contents` 的类型的情况下,我们需要进行预防性检查,或者使用容易出错的类型断言。
```ts twoslash
interface Box {
@@ -613,16 +582,16 @@ let x: Box = {
contents: "hello world",
};
-// we could check 'x.contents'
+// 我们可以检查‘x.contents’
if (typeof x.contents === "string") {
console.log(x.contents.toLowerCase());
}
-// or we could use a type assertion
+// 或者我们可以使用类型断言
console.log((x.contents as string).toLowerCase());
```
-One type safe approach would be to instead scaffold out different `Box` types for every type of `contents`.
+一种类型安全的方法是为每种类型的 `contents` 创建不同的 `Box` 类型。
```ts twoslash
// @errors: 2322
@@ -639,7 +608,7 @@ interface BooleanBox {
}
```
-But that means we'll have to create different functions, or overloads of functions, to operate on these types.
+但这样的话,我们将不得不创建不同的函数或函数的重载来操作这些类型。
```ts twoslash
interface NumberBox {
@@ -662,10 +631,9 @@ function setContents(box: { contents: any }, newContents: any) {
}
```
-That's a lot of boilerplate. Moreover, we might later need to introduce new types and overloads.
-This is frustrating, since our box types and overloads are all effectively the same.
+有很多样板代码。而且,以后我们可能需要引入新的类型和重载。这很令人沮丧,因为我们的盒子类型和重载实际上是相同的。
-Instead, we can make a _generic_ `Box` type which declares a _type parameter_.
+相反,我们可以创建声明_类型参数_的_泛型_ `Box` 类型。
```ts twoslash
interface Box