TS官方手册:TypeScript: Handbook – The TypeScript Handbook (typescriptlang.org)

匿名与具名

对象类型的声明可以是匿名的,也可以使用interfacetype进行具名声明。

function greet(person: { name: string; age: number }) {  return "Hello " + person.name;}
interface Person {  name: string;  age: number;} function greet(person: Person) {  return "Hello " + person.name;}
type Person = {  name: string;  age: number;}; function greet(person: Person) {  return "Hello " + person.name;}

可选属性 optional

使用?标记:

interface PaintOptions {  shape: Shape;  xPos?: number;  yPos?: number;}

注:使用PaintOptions声明的对象,它的xPos属性会被初步推断为number | undefined类型。

可以使用条件语句或者解构+默认值的方式收束类型,排除undefined的情况:

function paintShape(opts: PaintOptions) {    let xPos = opts.xPos === undefined ? 0 : opts.xPos;    // xPos 的类型为number}
function paintShape({ shape, xPos = 0, yPos = 0 }: PaintOptions) {// xPos 的类型为number,因为undefined会被默认值0取代    console.log("x coordinate at", xPos);}

只读属性 readonly

interface SomeType {    readonly prop: string;}

注:如果有一个属性的值是引用值,例如一个对象或数组,且这个属性被标记为只读(readonly),我们不能修改它的引用值,但是可以修改它的内部属性。

interface Home {  readonly resident: { name: string; age: number };}function visitForBirthday(home: Home) {  // 我们可以读取并且更新'home.resident'里的属性  console.log(`Happy birthday ${home.resident.name}!`);  home.resident.age++;} function evict(home: Home) {  // 但我们不能更新'home.resident'本身  home.resident = {Cannot assign to 'resident' because it is a read-only property.    name: "Victor the Evictor",    age: 42,  };}

索引签名 index signatures

interface StringArray {  [index: number]: string;} const myArray: StringArray = getStringArray();const secondItem = myArray[1];

索引的类型只能是:stringnumbersymbol,以及与这些类型相关的联合类型。

通常只会考虑stringnumber类型的索引。

:可以同时支持stringnumber两种类型的索引器,但数字索引器返回的类型必须是字符串索引器返回类型的子类型。这是因为当使用数字进行索引时,JS 实际上会在索引到对象之前将其转换为字符串。于是使用100"100"进行索引的结果是一样的。

当指定string类型索引的类型为S后,所有属性的类型都需要是S的子集。

interface NumberDictionary {    [index: string]: number;    length: number; // ok    name: string; // NOT ok}

这是因为当我们访问obj.a的时候,其实也是在访问obj["a"]

在上面这个例子中,string类型索引被声明为number类型,这意味着这个对象的所有属性都是number类型,而下方name却被声明为string类型,矛盾了。

可以使用联合类型解决这个问题:

interface NumberDictionary {    [index: string]: number | string;    length: number; // ok    name: string; // ok}

同时,索引签名也可以设置为只读:

interface ReadonlyStringArray {  readonly [index: number]: string;}

类型继承

使用extends,支持多继承:

interface Colorful {    color: string;} interface Circle {    radius: number;} interface ColorfulCircle extends Colorful, Circle {} const cc: ColorfulCircle = {    color: "red",    radius: 42,};

交集类型 intersection types

使用&运算符获取已知的两个类型的交集。

interface Colorful {  color: string;}interface Circle {  radius: number;} type ColorfulCircle = Colorful & Circle;

将两个基本数据类型取交集会得到never

类型继承 VS 交集类型

二者都可以产生更复杂的类型。

前者是在原有的类型的基础上添加可能未有的属性形成新属性,而后者将已有的类型进行组合。

泛型对象类型 Generic Object Types

interface Box {  contents: Type;}let box: Box;

也可以与泛型函数结合使用:

function setContents(box: Box, newContents: Type) {  box.contents = newContents;}

除了使用interface,也可以使用type别名定义泛型类型。interface一般用来声明对象类型,而type更灵活,可以组合多种类型:

type OrNull = Type | null;type OneOrMany = Type | Type[];// type OneOrManyOrNull = OneOrMany | nulltype OneOrManyOrNull = OrNull<OneOrMany>;// type OneOrManyOrNullStrings = OneOrMany | nulltype OneOrManyOrNullStrings = OneOrManyOrNull;