跳到主要内容

对象类型

定义一个对象类型可以用 interfacetype 定义:

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 支持 stringnumber 类型作为索引,但是 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` 方法

参考

Object Types - TypeScript