TypeScript基础笔记mk

interface接口

  1. 对对象形状(shape)进行描述:属性、方法进行描述
  2. 对class进行抽象:面向对象语言中,对class进行抽象,具体功能要类自己去实现
  3. duck typing(鸭子类型):某个东西长得像鸭子,能像鸭子一样走路游泳嘎嘎叫,就可以被看做是鸭子,主要关注对象怎么被使用,而不是类型本身

 

 新鲜度的问题,其实就是你如果直接用字面量,那么这个字面量每次都是新的,不是引用,而是新的内存,如果你用一个变量,相当于是一个指针/引用,没有新鲜度,所以不会报错。

注意可选属性的作用,可以用在这里。

函数 + 类型推断

枚举:

 默认从零开始

默认从0开始,如果我人为不从0开始呢

 编译出如下结果

 如果这么搞:

编译结果如下:

字符串枚举

编译如下:

常量枚举:

 多了个const,但是我们看看编译后的代码:太简洁了。直接把值翻译成结果,提升了性能。

枚举的值有两种类型:一种是常量值,一种是计算值 ,只有常量值可以进行常量枚举。

 泛型:Generics

function echo(arg) {
  console.log(arg)
}

const res = echo(123)
// 上面没法控制res的类型啊,等于是参数是any,返回是any,
// 而且两个any可以不一样,不过后面的版本TS自动修复了这个问题
function echo<T>(arg: T): T{
  console.log(arg)
  return arg
}

const n: number = 12
const res = echo(n)
function echo<T>(arg: T): T{
  console.log(arg)
  return arg
}

// const n: number = 12
// const res = echo(n)
// 其实可以类型推断
const res = echo(12)

上图中,res[1]已经变为'string'了,具有String类型的所有方法。

约束泛型

前面讲的比较简单,都是参数和返回值的一些简单用法,那么泛型使用的地方还很多,比如用到类上。实现如下场景:进入队列、离开队列。

但是,我们如果某天不是用number类型了,而是使用string类型。那么我们还有修改很多代码。这是不合理的,现在我们约束push什么类型,pop出来就什么类型,保持一致。创建一个泛型类。

const queue2 = new Queue<string>()
queue2.push('hello')
console.log(queue2.pop().length)

 上面的类可以用泛型描述,那么interface也可以用泛型描述

interface KeyPair<T, U> {
  key: T
  value: U
}

let kp1: KeyPair<number, string> = { key: 100, value: 'hello' }
let kp2: KeyPair<string, number> = { key: 'test', value: 211 }
interface KeyPair<T, U> {
  key: T
  value: U
}

let kp1: KeyPair<number, string> = { key: 100, value: 'hello' }
let kp2: KeyPair<string, number> = { key: 'test', value: 211 }

// 下面就是我们很眼熟的操作了
let arr: number[] = [1, 2, 3]
let brr: Array<number> = [1, 2, 3]

还可以用interface来描述函数的type

function plus(a: number, b: number): number {
  return a + b
}

function connect(a: string, b: string): string {
  return a + b
}

// 我们可以用interface来描述这个函数的类型
interface IPlus {
  (a: number, b: number): number // 描述了一个函数类型
}
// 更进一步,加个参数
interface IPlus1<T> {
  (a: T, b: T): T
}

const b: IPlus1<number> = plus
const c: IPlus1<string> = connect

 上面就很灵活了。

类型别名

// 类型别名  type aliases  给类型起个别名
function sum(x: number, y: number): number {
  return x + y
}
// 假设有个sum2等于sum,虽然直接下面写法就可以了,可以直接推断出来
const sum2 = sum
// 但是,如果要手动显示写sum2的类型,就要写半天麻烦
const sum3: (x: number, y: number) => number = sum

// 为了解决这个问题,就有了类型别名,用关键字type
type PlusType = (x: number, y: number) => number
const sum4: PlusType = sum

// 再看一个场景:参数n可能是字符串类型,直接返回,也可能是函数,返回函数的执行结果。类型别名
type NameResolver = () => string
type NameOrResolver = string | NameResolver
function getName(n: NameOrResolver): string {
  if (typeof n === 'string') {
    return n
  } else {
    return n()
  }
}

类型断言 type assertion

当ts不确定一个联合类型的变量,到底是哪个类型的时候,我们只能访问此联合类型的共用的属性和方法,有时候在还不确定类型的时候,就要访问其中一个类型的属性和方法。

联合类型,只能访问共同部分,上面string | number 的联合体,string有length,number没有,你就贸然用input.length,很可能纠错了,所以ts直接阻止了这么做。

这个时候采用类型断言。

function getLength(input: string | number): number {
  const str = input as String
  if (str.length) {
    return str.length
  } else {
    const number = input as Number
    return number.toString.length
  }
}


function getLength1(input: string | number): number {
  // 在要断言的变量前添加一个尖括号,语法要记住
  if((<string>input).length) {
    return (<string>input).length
  } else {
    return input.toString().length
  }
}

// 类型断言不是类型转换,你要是把它断言成联合类型中不存在的类型,那也是不行的
// 比如 input是 string | number,你要是把它断言成boolean那肯定不行