# 对象类型


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

interface Person {
  name: string;
  age: number;
}

function greet(person: Person) {
  return "Hello " + person.age;
}

type Person = {
  name: string;
  age: number;
};

function greet(person: Person) {
  return "Hello " + person.age;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 属性修饰符

# 可选属性 ?

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

function paintShape(opts: PaintOptions) {
  // ...
}

const shape = getShape();
paintShape({ shape });
paintShape({ shape, xPos: 100 });
paintShape({ shape, yPos: 100 });
paintShape({ shape, xPos: 100, yPos: 100 });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# readonly 属性

interface SomeType {
  readonly prop: string;
}

interface Home {
  readonly resident: { name: string; age: number }; 
}

function visitForBirthday(home: Home) {
  // We can read and update properties from 'home.resident'.
  console.log(`Happy birthday ${home.resident.name}!`);
  home.resident.age++;
}

function evict(home: Home) {
  // Cannot assign to 'resident' because it is a read-only property.

  home.resident = {
    name: "Victor the Evictor",
    age: 42,
  };
}


// 可以被重写


interface Person {
  name: string;
  age: number;
}

interface ReadonlyPerson {
  readonly name: string;
  readonly age: number;
}

let writablePerson: Person = {
  name: "Person McPersonface",
  age: 42,
};

// works
let readonlyPerson: ReadonlyPerson = writablePerson;

console.log(readonlyPerson.age); // prints '42'
writablePerson.age++;
console.log(readonlyPerson.age); // prints '43'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

# 索引签名

有时我们可能不知道类型属性的名称,但是我们知道属性对应值的类型。此时可以用索引签名

var user = {
    1:1,
    2:2,
    3:3,
    sex: "男",
    name:'曹泽鹏'
}


1
2
3
4
5
6
7
8
9

下面索引签名指出,当用数字对StringArray进行索引时,它将返回一个字符串。

  interface StringArray {
    [index: number]: string;
  }
  
  const myArray: StringArray = ['a', 'b','d'];
  const secondItem = myArray[1]; // string
1
2
3
4
5
6

# 注意

:::waring 可以同时支持两种类型的索引器,但是从数字索引器返回的类型必须是从字符串索引器返回的类型的子类型。这是因为在使用数字索引时, JavaScript实际上会在将其索引到对象之前将其转换为字符串。这意味着用100(一个数字)进行索引与用“ 100”(一个字符串)进行索引是同一回事,

:::

interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// Error: indexing with a numeric string might get you a completely separate type of Animal!
// Numeric index type 'Animal' is not assignable to string index type 'Dog'.
interface NotOkay {
  [x: number]: Animal;
  [x: string]: Dog;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

索引签名是 字符串,表示用字符串对NumberDictionary进行索引时返回数字,而name返回string,所以name报错了

interface NumberDictionary {
  [index: string]: number;

  length: number; // ok
  name: string;
 // Property 'name' of type 'string' is not assignable to string index type 'number'.
}
1
2
3
4
5
6
7

可以将索引签名设置为只读

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

let myArray: ReadonlyStringArray = getReadOnlyStringArray();
myArray[2] = "Mallory";
// Index signature in type 'ReadonlyStringArray' only permits reading. ❌
1
2
3
4
5
6
7

# 扩展类型

可以通过extends进行类型扩展

interface BasicAddress {
  name?: string;
  street: string;
  city: string;
  country: string;
  postalCode: string;
}

interface AddressWithUnit extends BasicAddress {
  unit: string;
}
1
2
3
4
5
6
7
8
9
10
11

多继承

interface Colorful {
  color: string;
}

interface Circle {
  radius: number;
}

interface ColorfulCircle extends Colorful, Circle {
    age: number;
}

const cc: ColorfulCircle = {
  color: "red",
  radius: 42,
  age:100
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 交叉类型

只是组合不做扩展

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

  var color: ColorfulCircle = {
    color:'1',
    radius: 1,
    border: 1
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 交叉类型和接口区别

交叉类型和接口都可以实现扩展,主要区别是如何处理冲突,当两个类型的属性重复的时候。

# 泛型 对象类型

简单示例

interface Box<Type> {
  contents: Type;
}

type Box<Type> = {
  contents: Type;
};

interface StringBox {
  contents: string;
}

let boxA: Box<string> = { contents: "hello" };
boxA.contents;
        
(property) Box<string>.contents: string

let boxB: StringBox = { contents: "world" };
boxB.contents;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

示例二


interface Box<Type> {
  contents: Type;
}

type Box<Type> = {
  contents: Type;
};

interface Apple {
  // ....
}

// Same as '{ contents: Apple }'.
type AppleBox = Box<Apple>;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function setContents<Type>(box: Box<Type>, newContents: Type) {
  box.contents = newContents;
}
1
2
3

由于type别名与interface不同,它不仅可以描述对象类型,所以我们还可以使用它们来编写其他类型的通用帮助程序类型。

type OrNull<Type> = Type | null;

type OneOrMany<Type> = Type | Type[];

type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>;
           
type OneOrManyOrNull<Type> = OneOrMany<Type> | null

type OneOrManyOrNullStrings = OneOrManyOrNull<string>;
               
type OneOrManyOrNullStrings = OneOrMany<string> | null
1
2
3
4
5
6
7
8
9
10
11

数组泛型

interface Array<Type> {
  /**
   * Gets or sets the length of the array.
   */
  length: number;

  /**
   * Removes the last element from an array and returns it.
   */
  pop(): Type | undefined;

  /**
   * Appends new elements to an array, and returns the new length of the array.
   */
  push(...items: Type[]): number;

  // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 数组泛型

Array<number> 或者 Array<string>.

# 只读数组类型 ReadonlyArray

readonly string[] 或者 ReadonlyArray<string> 不能用数组泛型Array<string>表示

# 元祖类型

组类型是另一种Array类型,它确切地知道它包含多少个元素,以及确切地在特定位置包含什么类型。 type StringNumberPair = [string, number];

type StringNumberPair = [string, number];
type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];


function readButtonInput(...args: [string, number, ...boolean[]]) {
  const [name, version, ...input] = args;
  // ...
}

function readButtonInput(name: string, version: number, ...input: boolean[]) {
  // ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

只读元祖

function doSomething(pair: readonly [string, number]) {
  // ...
}
1
2
3

将正常数组改为元祖

let point = [3, 4] as const;

function distanceFromOrigin([x, y]: [number, number]) {
  return Math.sqrt(x ** 2 + y ** 2);
}

distanceFromOrigin(point);
1
2
3
4
5
6
7