对象类型
定义一个对象类型可以用 interface
或 type
定义:
interface Person {
name: string;
age: number;
}
type Person = {
name: string;
age: number;
};
或者直接匿名定义:
function greet(person: { name: string; age: number }) {
return 'Hello ' + person.name;
}
属性修饰器
可选属性
在属性后面标记 ?
代表它是可选的,这个属性在使用时将可能为 undefined
:
interface PaintOptions {
shape: Shape;
xPos?: number; // `xPos` 的类型为 `number | undefined`
yPos?: number; // 同上
}
只读属性
在属性前标记 readonly
表示其不可修改(仅作类型检查用,不会有任何副作用):
interface SomeType {
readonly prop: string;
}
function doSomething(obj: SomeType) {
obj.prop = 'hello'; // ERROR: 无法给只读属性赋值
}
索引签名
指定一个索引签名:
interface StringArray {
[index: number]: string;
}
const stringArray = ['hello', 'world'];
const secondItem = stringArray[1]; // => 'world'
设置索引签名代表所有的属性都必须为其返回值类型的子类型:
interface NumberDictionary {
[index: string]: number;
length: number;
name: string; // ERROR: `name` 的类型不符合 string 索引签名
}
JS 支持 string
和 number
类型作为索引,但是 number
会隐式转为 string
去访问。TS 中也可以同时定义两种类型的索引,但是 number
索引的返回值类型必须是 string
索引的子类型:
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
interface NotOkay {
[x: number]: Animal;
[x: string]: Dog; // ERROR: `Animal` 类型不能赋值给 `Dog` 类型
}
类型扩展
使用 extends
扩展一个类型:
interface BasicAddress {
name?: string;
street: string;
city: string;
country: string;
postalCode: string;
}
interface AddressWithUnit extends BasicAddress {
unit: string;
}
类型合并
除了类型扩展,也可以用 &
直接合并两个类型:
interface Colorful {
color: string;
}
interface Circle {
radius: number;
}
type ColorfulCircle = Colorful & Circle;
泛型
interface Box<Type> {
contents: Type;
}
const box: Box<string> = { contents: 'item' };
function setContents<Type>(box: Box<Type>, newContents: Type) {
box.contents = newContents;
}
常见的泛型类型有:Array<T>
Map<K, V>
Set<T>
Promise<T>
。
Array
类型
number[]
和 string[]
仅仅是 Array<number>
和 Array<string>
的缩写。
ReadonlyArray
ReadonlyArray
类型表示数组自身不允许进行修改,它删除了一些能修改自身的方法:
const a: ReadonlyArray<number> = [1, 2, 3];
a.concat([4, 5, 6]); // => [1, 2, 3, 4, 5, 6]
a[2] = 5; // ERROR: 索引属性只读
a.push(4); // ERROR: 没有 `push` 方法
a.pop(); // ERROR: 没有 `pop` 方法
ReadonlyArray<T>
可以缩写为readonly T[]
。
ReadonlyArray 不可以赋值给 Array :
let x: readonly string[] = [];
let y: string[] = [];
x = y;
y = x; // ERROR: 只读数组不能赋值给可变数组
ReadonlyArray
只能用作类型,它没有构造方法:
// ERROR: `ReadonlyArray` 是一种类型,但这里却用作为值
new ReadonlyArray('red', 'green', 'blue');
元组
元组是数组的一种,它限定了数组的长度,同时可以指定每一位元素的类型:
type Pair = [string, number];
const pair: Pair = ['hello', 20];
pair[0]; // => 'hello'
pair[1]; // => 20
pair[2]; // ERROR: 长度为 2 的元组没有该索引
元组的元素类型可以为可选,但只能放在数组末尾,数组的长度也会受到影响:
// 该类型的数组长度为 `2 | 3`
type Either2dOr3d = [number, number, number?];
也可以不用可选语法,直接明确元素类型为
number | undefined
来获得一个固定长度的数组,且不必放在数组末尾。
元组可以有剩余元素(不必放在数组末尾),它必须是一个数组或元组类型:
// 这些类型将不会有固定的数组长度
type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];
const a: StringNumberBooleans = ['world', 3, true, false, true, false, true];
在函数中,剩余形参可以为带剩余元素的元组类型:
function readButtonInput(...args: [string, number, ...boolean[]]) {
const [name, version, ...input] = args;
// ...
}
剩余元素不在末尾的元组也可以作为剩余形参,但是 JS 原本的数组解构语法不能将剩余语法放在非末尾的位置。
只读元组
在元组类型前加上 readonly 可以禁止数组的修改:
const a: readonly [number, string] = [1, 'hello'];
a[0] = 10; // ERROR: 索引 0 为只读
对一个数组字面量使用 const 断言将被推断为一个只读元组:
let point = [3, 4] as const;
point[2]; // ERROR: 长度为 2 的元组没有该索引
point.pop(); // ERROR: 没有 `pop` 方法