TypeScript 初学笔记-类型操

TypeScript笔记

1. 基本类型

JS内置类型、全局作用域 global 上存在的对象(Window内属性对象):Array、Date、Error 等、HTMLElement、NodeList、MouseEvent 等。

2. 数组、元祖、函数类型

元组类型允许表示一个【已知元素数量和类型】的数组,各元素的类型不必相同。(需要提前定义类型)

let tuple: [number, string] = [18, 'lin']

函数类型不返回则默认为void,可选变量放在最后且变量后加 即可。
函数重载则是将定义一个个叠起来,最后统一使用any实现,在函数体内判断类型。
永不返回或者抛出Error的函数可以使用 never 作为返回类型

// 异常
function fn(msg: string): never { 
  throw new Error(msg)
}

// 死循环 千万别这么写,会内存溢出
function fn(): never { 
  while (true) {}
}

3. class、interface、implements

  1. class新增了public、private、protected类型限制和抽象类型abstract。使用extends实现继承。
class Animal{
  name:string
  constructor(name:string) {
    this.name = name
  }
  speak() {
    console.log(this.name)
  }
}

class Dog extends Animal{
  voice:string
  constructor(name:string,voice:string) {
    super(name);
    this.voice = voice;
  }

  speak(): void {
      console.log(this.name,this.voice)
  }

const dog = new Dog('xiao gou','wangwang')
  1. interface 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。

  2. interface可以对class进行约束,通过使用implements(实现)。

interface speakInterface {
  speak(): void
}
interface otherInterface {
  name: string
  arr:string[]
  // [propName: string]: string // 自定义属性
  // 自定义属性需要注释掉否则会提示Animal错误实现接口。
}
interface newInterface {
  new (propsName: string): void
}

class Animal implements speakInterface,otherInterface,newInterface{
  name='aaa';
  arr=['1','2','3']
  speak(){
  }
}

4. interface与数组与鸭子类型(duck typing)

interface 写法灵活且可以支持多种自定义类型,它还有个别称叫 鸭子类型。【当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。】
只要数据满足了 interface 定义的类型,哪怕它其实一点也不是,TS 仍可以编译通过。

举例1:使用interface实现一个数组结构(但是它不是真的数组,没有数组相关的方法)

interface arrInterface {
  [index:number]: string
}

const arr:arrInterface=['1','2','3']
// arr.length 报错:类型“arrInterface”上不存在属性“length”

举例2:使用interface定义函数和函数上的属性

interface funcInterface {
  (x:number):void
  name:string
}
const test:funcInterface = (x:number) => { }

test.a = '111' // 类型“funcInterface”上不存在属性“a”
test.name = '111' // 可以

5. interface与type

平时开发中,一般使用组合或者交叉类型的时候,用 type。
一般要用类的 extends 或 implements 时,用 interface。
其他情况,比如定义一个对象或者函数,就看你心情了。

类型别名会给一个类型起个新名字。类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

type Name = string                              // 基本类型
type arrItem = number | string                  // 联合类型
const arr: arrItem[] = [1,'2', 3]

type Person = { 
  name: Name 
}

type Student = Person & { grade: number  }       // 交叉类型
type Teacher = Person & { major: string  } 
type StudentAndTeacherList = [Student, Teacher]  // 元组类型

const list:StudentAndTeacherList = [
  { name: 'lin', grade: 100 }, 
  { name: 'liu', major: 'Chinese' }
]

有相似功能却不同的两种定义数据类型的方式。

  • 相同点
    1. 都可以定义一个对象或函数
    2. 都允许继承。interface 使用 extends 实现继承, type 使用交叉类型实现继承。
      • interface通过extends可以继承interface / type
      • type通过&继承属性,可以继承interface / type定义的类型。
    // 这两种写法都可以定义函数类型
    type addType = (num1:number,num2:number) => number
    
    interface addType {
        (num1:number,num2:number):number
    }
    
  • 不同点
    1. interface(接口) 是 TS 设计出来用于【定义对象类型】的,可以对对象的形状进行描述。
    2. type 是类型别名,用于给各种类型定义别名,让 TS 写起来更简洁、清晰。
    3. type 可以声明基本类型、联合类型、交叉类型、元组,interface 不行
    4. interface可以合并重复声明,type 不行。
    interface Person {
      name: string
    }
    
    interface Person {         // 重复声明 interface,就合并了
      age: number
    }
    
    const person: Person = {
      name: 'lin',
      age: 18
    }
    

6. 泛型

举例使用泛型:在不知道可能会传入什么类型的变量前提下,为了约束函数中进、出是同一种而采用的类型占位符。

// type / interface、函数都可以使用泛型
// type Print = <T>(arg: T) => T
interface Print<T> {
  (arg:T):T
}
interface Print1<T,U> {
  (arg:T):T
  name:U
}

const printFn:Print<string> = function Print(arg) {
  console.log(arg)
  return arg
}
function test<T>(param:T):T{
  return param;
}
const str:string = test<string>('12121')

// class / 数组定义等也可以使用泛型
class Test<T>{
  print(arg:T):T|undefined{
    return arg;
  }
}
const str = new Test<string>()

const arr:Array<number> = [1,2,3] // const arr: number[] = [1,2,3]

搞懂了什么是泛型之后,现在我们可以尝试使用和约束泛型。精确约束内部属性主要可以使用extends。笔记中我分为属性约束和副作用(内部函数)约束

// 属性约束
function printLength<T>(arg: T): T {
  console.log(arg.length)
  return arg
}
// 报错,因为不确定arg上是否有length属性,这时就可以使用interface / extends去约束
interface ILength {
  length: number
}

function printLength<T extends ILength>(arg: T): T {
    console.log(arg.length)
    return arg
}

// 副作用约束
// 一个公共方法(不确定传入值),内部异步调用(不确定回传),如下,默认的res返回是any,无法得到类型约束
function request(url:string) {
  return fetch(url).then(res => res.json())
}
// 为了更好地约束res回传值,我们可以使用泛型
interface UserInfo {
  name: string
  age: number
}

function request<T>(url:string): Promise<T> {
    return fetch(url).then(res => res.json())
}
 
request<UserInfo>('user/info').then(res =>{
    console.log(res)
})

索引类型 —— 我的理解中,索引类型是用于进一步简化复杂的约束操作而定义的几个方法,其中的约束仍然是针对于属性约束。
主要可以实现实现动态属性的检查 keyof(索引查询)、T[K](索引访问) 和 extends (泛型约束)。

// keyof(索引查询) 可以用于获取某种类型的所有键,其返回类型是联合类型。
interface IPerson {
  name: string;
  age: number;
}
type Test = keyof IPerson; // 'name' | 'age'

// T[K](索引访问) 表示接口 T 的属性 K 所代表的类型,
interface IPerson {
  name: string;
  age: number;
}
let type1:  IPerson['name'] // string

// T extends U,表示泛型变量可以通过继承某个类型 同上文

泛型约束使用题目: 下方的变量中使用原本没有的属性却没有提示,该如何纠正?

const userInfo = {
  name: 'lin',
  age: '18',
}

function getValues(userInfo: any, keys: string[]) {
  return keys.map(key => userInfo[key])
}

// 抽取指定属性的值
console.log(getValues(userInfo, ['name','age']))  // ['lin', '18']
// 抽取obj中没有的属性:(并没有报错)
console.log(getValues(userInfo, ['sex','outlook']))  // [undefined, undefined]

// 原本定义了一个interface userInfo,但是公用函数中最好都使用泛型占位、让函数实例填充,而不是指定具体类型
function getValues<T,K extends keyof T>(userInfo: T, keys: K[]) {
  return keys.map(key => userInfo[key])
}

console.log(getValues(userInfo, ['name','age']))  
console.log(getValues(userInfo, ['sex','outlook'])) 

7、其他简便运算符号:in、Pick、Partial、Exclude、Omit、Extract等

// in 用于遍历联合类型
type Person = "name" | "school" | "major"
type Obj =  {
  [p in Person]: string
}

// Partial 将类型映射成可选属性
interface IPerson {
  name: string
  age: number
}
type IPartial = Partial<IPerson>
let p1: IPartial = {}

8. TypeScript声明文件d.ts

如果项目是js写的,后面需要接进ts项目,那需要写一个.d.ts的声明文件来告诉外部的ts检测 我这个是什么类型,我这里已经定义了,不需要您的类型检查了。如果是ts项目那就不需要额外书写声明文件。 大部分项目的声明都放在@types/xx 这个依赖中,直接npm到项目就可以了。
declare class Test {}
以上是将HTML代码转换为Markdown格式的文本。

  • 21
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值