类型推论

如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型。

如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查

  1. let myFavoriteNumber;
  2. myFavoriteNumber = 'seven';
  3. myFavoriteNumber = 7;

联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种。

  1. let myFavoriteNumber: string | number;
  2. myFavoriteNumber = 'seven';
  3. myFavoriteNumber = 7;

联合类型使用 | 分隔每个类型。

这里的 let myFavoriteNumber: string | number 的含义是,允许 myFavoriteNumber 的类型是 string 或者 number,但是不能是其他类型。

联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型

  1. let myFavoriteNumber: string | number;
  2. myFavoriteNumber = 'seven';
  3. console.log(myFavoriteNumber.length); // 5
  4. myFavoriteNumber = 7;
  5. console.log(myFavoriteNumber.length); // 编译时报错
  6. // index.ts(5,30): error TS2339: Property 'length' does not exist on type 'number'.

上例中,第二行的 myFavoriteNumber 被推断成了 string,访问它的 length 属性不会报错。

而第四行的 myFavoriteNumber 被推断成了 number,访问它的 length 属性时就报错了。


类型注解

  1. function greeter (person: string) {
  2. return 'Hello, ' + person
  3. }
  4. let user = 'Yee'
  5. console.log(greeter(user))

person 函数的参数添加 : string 类型注解

接口

TypeScript 的核心原则之一是对值所具有的结构进行类型检查。我们使用接口(Interfaces)来定义对象的类型。接口是对象的状态(属性)和行为(方法)的抽象(描述)

  1. interface Persion {
  2. // 只读
  3. readonly id: number;
  4. name: string;
  5. age: number;
  6. // 卡哇伊没有 sex 属性
  7. sex?: string;
  8. };
  9. const person: Persion = {
  10. id: 1,
  11. name: "ade kang",
  12. age: 18,
  13. };
  14. console.log(person);

定义的变量比接口少了一些属性是不允许的,当然多一些属性也是不允许的。

只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

类的类型

可以通过接口来实现

  1. (() => {
  2. interface IFLY {
  3. fly(): any;
  4. }
  5. class Person implements IFLY {
  6. fly() {
  7. console.log("---");
  8. }
  9. }
  10. const p1 = new Person();
  11. p1.fly();
  12. })();

定义一个接口继承其他接口(接口与接口叫继承 extends)

  1. interface LightableAlarm extends IFLY, Light {
  2. }

一个类可以实现多个接口(类和接口叫实现 implements )

  1. class Car2 implements Alarm, Light {
  2. alert() {
  3. console.log('Car alert');
  4. }
  5. lightOn() {
  6. console.log('Car light on');
  7. }
  8. lightOff() {
  9. console.log('Car light off');
  10. }
  11. }

函数

泛型

指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型的一种特性。先将位置占这,然后再使用的时候再给定相关类型

  1. function createArray2 <T> (value: T, count: number) {
  2. const arr: Array<T> = []
  3. for (let index = 0; index < count; index++) {
  4. arr.push(value)
  5. }
  6. return arr
  7. }
  8. const arr3 = createArray2<number>(11, 3)
  9. console.log(arr3[0].toFixed())
  10. // console.log(arr3[0].split('')) // error
  11. const arr4 = createArray2<string>('aa', 3)
  12. console.log(arr4[0].split(''))
  13. // console.log(arr4[0].toFixed()) // error

多个泛型参数的函数

  1. function swap <K, V> (a: K, b: V): [K, V] {
  2. return [a, b]
  3. }
  4. const result = swap<string, number>('abc', 123)
  5. console.log(result[0].length, result[1].toFixed())

泛型接口

在定义接口时, 为接口中的属性或方法定义泛型类型
在使用接口时, 再指定具体的泛型类型

  1. interface IbaseCRUD <T> {
  2. data: T[]
  3. add: (t: T) => void
  4. getById: (id: number) => T
  5. }
  6. class User {
  7. id?: number; //id主键自增
  8. name: string; //姓名
  9. age: number; //年龄
  10. constructor (name, age) {
  11. this.name = name
  12. this.age = age
  13. }
  14. }
  15. class UserCRUD implements IbaseCRUD <User> {
  16. data: User[] = []
  17. add(user: User): void {
  18. user = {...user, id: Date.now()}
  19. this.data.push(user)
  20. console.log('保存user', user.id)
  21. }
  22. getById(id: number): User {
  23. return this.data.find(item => item.id===id)
  24. }
  25. }
  26. const userCRUD = new UserCRUD()
  27. userCRUD.add(new User('tom', 12))
  28. userCRUD.add(new User('tom2', 13))
  29. console.log(userCRUD.data)

泛型类

在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型

  1. class GenericNumber<T> {
  2. zeroValue: T
  3. add: (x: T, y: T) => T
  4. }
  5. let myGenericNumber = new GenericNumber<number>()
  6. myGenericNumber.zeroValue = 0
  7. myGenericNumber.add = function(x, y) {
  8. return x + y
  9. }
  10. let myGenericString = new GenericNumber<string>()
  11. myGenericString.zeroValue = 'abc'
  12. myGenericString.add = function(x, y) {
  13. return x + y
  14. }
  15. console.log(myGenericString.add(myGenericString.zeroValue, 'test'))
  16. console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))

内置对象

JavaScript 中有很多内置对象,它们可以直接在 TypeScript 中当做定义好了的类型。

内置对象是指根据标准在全局作用域(Global)上存在的对象。这里的标准是指 ECMAScript 和其他环境(比如 DOM)的标准。

  1. ECMAScript 的内置对象

Boolean
Number
String
Date
RegExp
Error

  1. /* 1. ECMAScript 的内置对象 */
  2. let b: Boolean = new Boolean(1)
  3. let n: Number = new Number(true)
  4. let s: String = new String('abc')
  5. let d: Date = new Date()
  6. let r: RegExp = /^1/
  7. let e: Error = new Error('error message')
  8. b = true
  9. // let bb: boolean = new Boolean(2) // error
  1. BOM 和 DOM 的内置对象

Window
Document
HTMLElement -> HTML标签
DocumentFragment
Event
NodeList

  1. const div: HTMLElement = document.getElementById('test')
  2. const divs: NodeList = document.querySelectorAll('div')
  3. document.addEventListener('click', (event: MouseEvent) => {
  4. console.dir(event.target)
  5. })
  6. const fragment: DocumentFragment = document.createDocumentFragment()

类型断言

类型断言(Type Assertion)可以用来手动指定一个值的类型。也就是我知道这个了类型。

语法§

  1. as 类型

  1. <类型>值

在 tsx 语法(React 的 jsx 语法的 ts 版)中必须使用前者,即 值 as 类型