TS笔记

280 阅读10分钟

TS学习

基本类型

void

void只能接受undeinfed或者作为函数的返回值类型,

let u:void=undefined

function fnVOid():void{} 函数就不能有返回值

void和undefined、null的区别

void值是不可以赋值给其他类型的

let str: string = '123'
let v: void = undefined
~~~str = v~~~ 这样会报错

image.png

任意类型

any

any没有强制限定类型,可以对any类型的变量进行任何操作,不需要检查类型。和原生js一样了

常用any的两个地方

从服务器取得了很复杂的数据(有时间可以一个个定义,没时间直接any)。

type People = {
  name: string
  age: number
  [propName: string]: any  //剩余参数类型定义为any
}
let people: People = {
  name: 'zds',
  age: 12,
  score: [1, 2],
}

引入一些第三方库时,缺失了类型注解

unknow

let unknow: unknown = { a: 123 }
unknow.a 会报错。
unknow比any更安全,不能调用属性和方法,而如果是any类型就不会报错。

对象类型

interface接口

接口实际上是一种约束,给对象的属性定义数据类型约束

//这样写是会报错的 因为我们在person定义了ab但是对象里面缺少b属性
//使用接口约束的时候不能多一个属性也不能少一个属性
//必须与接口保持一致
interface Person {
    b:string,
    a:string
}
 
const person:Person  = {
    a:"213"
}

但是可以通过可选操作符实现

//可选属性的含义是该属性可以不存在
//所以说这样写也是没问题的
interface Person {
    b?:string,
    a:string
}
 
const person:Person  = {
    a:"213"
}

重名的interface可以合并

//重名的interface可以用于合并
interface A {
  name: string
}
interface A {
  age: number
}
let x: A = {
  name: 'zds',
  age: 123
}

任意类型

比如后端返回了一个带有杂七杂八属性的对象,但是前端只需要name和age属性,如何定义数据类型。

image.png

只读属性 readonly

interface Mu {
    readonly a:string
}

image.png

定义对象里的函数类型

需要定义传入的参数类型和返回值类型。接口里定义的是参数类型和返回值类型,而赋值的对象里的函数需要定义传入的参数和返回值,留作调用

interface Axxis {
  cb: () => boolean
}
let a: Axxis = {
  cb: () => false
}

a.cb = () => true

image.png

接口的继承 extends

可以继承多个接口,用 , 分割

interface A {
  name: string
}
interface B {
  age: number
}
interface C extends A, B {
  score: number
}

let c: C = {
  name: 'zds',
  age: 12,
  score: 123
}

给函数定义类型

函数有两种创建方式:①声明式②变量式

声明式函数 定义类型: 一般来说对象里定义方法也都用的该方式

function Fn(name: string): number[] {
  return [123]
}

interface obj {
  fn: (name: string) => void
}

变量表达式创建的函数 定义类型用接口,但感觉没必要,不如直接定义参数类型和返回值类型。如果该类型需要使用多次,可以用接口方式定义函数类型

interface Fn {
  (name: string): number[]
}

const fn: Fn = () => {
  return [123]
}
const add: Add = (num1, num2) => {
  return num1 + num2
}

const jian = (num1: number, num2: number): number => {
  return num1 - num2
}

数组类型

类型[]

//类型加中括号
let arr:number[] = [123]
//这样会报错定义了数字类型出现字符串是不允许的
let arr:number[] = [1,2,3,'1']
//操作方法添加也是不允许的
let arr:number[] = [1,2,3,]
arr.unshift('1')
 
 
var arr: number[] = [1, 2, 3]; //数字类型的数组
var arr2: string[] = ["1", "2"]; //字符串类型的数组
var arr3: any[] = [1, "2", true]; //任意类型的数组

数组泛型 但是一般用的比较少,常用的还是类型[]

let arr: Array<number> = [123, 123]

配合interface定义对象数组 type也是可以的,但是type用的很少

interface X {
  name: string
  age: number
}

let arr: X[] = [{ name: '小曼', age: 12 }]

定义二维数组

方式① let arr: number[][] = [[1], [2]]

方式② 用的不多

image.png

大杂烩数组 let arr: any[] = [1, 'absd', false] 也可以用元组,即一一枚举,但是很麻烦

let num: [number, string, boolean] = [1, 'a', false]

在函数中使用 在函数剩余参数中使用


function Fn(...ages: number[]) {

  console.log(ages)

}

Fn(1, 2, 3)

给函数的arguments定义类型 ts内部提供了IArguments

函数扩展

定义函数类型的两种方式 声明式和变量表达式

function Fn(name: string): number[] {
  return [123]
}

interface obj {
  fn: (name: string) => void
}

变量表达式创建的函数 定义类型用接口

当然也可以写全,但是写全不就浪费时间麻烦了吗

interface Fn {
  (name: string): number[]
}

const fn: Fn = () => {
  return [123]
}

interface Add {
  (num1: number, num2: number): number
}
const add: Add = (num1, num2) => {
  return num1 + num2
}


函数的形参可选参数 不传是undefined

//通过?表示该参数为可选参数
const fn = (name: string, age?:number): string => {
    return name + age
}
fn('张三')

函数参数默认值

const fn = (name: string = "我是默认值"): string => {
    return name
}
fn()

函数重载

function fn(params: number): void
 
function fn(params: string, params2: number): void
 
 //上两个是重载函数,下面这个是执行函数,因为多了个params2,所以必须是可选,执行函数参数类型必须是any
function fn(params: any, params2?: any): void {
 
    console.log(params)
 
    console.log(params2)
 
}
 
fn(123)
 
fn('123',456)

image.png

联合类型 |

其实就是或 同时支持多个类型

let num: number | string = 1
let fn = function (type: number | boolean): boolean {
  return !!type
}
console.log(!!null);

交叉类型 &

其实就是and,就是必须同时满足两个类型

interface A {
  name: string
}
interface B {
  age: number
}
let C: A & B = {
  name: '123',
  age: 12
}

类型断言

语法: 值 as 类型 或者 <类型>值

需要注意的是,类型断言只能够「欺骗」TypeScript 编译器,无法避免运行时的错误,反而滥用类型断言可能会导致运行时错误: 常用第一种: value as string

image.png 解决办法:

let fn = function (num: number | string): void {
  //断言它是string类型,即使是number类型也不会报错,但是运行后是undefined
  console.log((num as string).length)
}
fn(123)

image.png

TS内置对象

Boolean、Number、stringRegExpDateError

let b: Boolean = new Boolean(1)
console.log(b)
let n: Number = new Number(true)
console.log(n)
let s: String = new String('哔哩哔哩')
console.log(s)
let d: Date = new Date()
console.log(d)
let r: RegExp = /^1/
console.log(r)
let e: Error = new Error("error!")
console.log(e)

DOM和BOM的内置对象

DocumentHTMLElementEventNodeList 等

常用的几个类型HTMLElement、MouseEvent、NodeList

let body: HTMLElement = document.body;

//读取所有节点 querySelectorAll()===>NodeList

let allDiv: NodeList = document.querySelectorAll('div');

//单独读取某一个元素 这种需要类型断言(是什么元素) 或者加个判断应为读不到返回null

let div:HTMLElement = document.querySelector('div')as HTMLDivElement

document.addEventListener('click', function (e: MouseEvent) {

});

Proimse

image.png

//返回Promise
function myPromise(): Promise<number> {
  return new Promise<number>((resolve, reject) => {
    resolve(1)
  })
}

myPromise().then(res => {
  console.log(res)
})

image.png


//dom元素的映射表
interface HTMLElementTagNameMap {
    "a": HTMLAnchorElement;
    "abbr": HTMLElement;
    "address": HTMLElement;
    "applet": HTMLAppletElement;
    "area": HTMLAreaElement;
    "article": HTMLElement;
    "aside": HTMLElement;
    "audio": HTMLAudioElement;
    "b": HTMLElement;
    "base": HTMLBaseElement;
    "bdi": HTMLElement;
    "bdo": HTMLElement;
    "blockquote": HTMLQuoteElement;
    "body": HTMLBodyElement;
    "br": HTMLBRElement;
    "button": HTMLButtonElement;
    "canvas": HTMLCanvasElement;
    "caption": HTMLTableCaptionElement;
    "cite": HTMLElement;
    "code": HTMLElement;
    "col": HTMLTableColElement;
    "colgroup": HTMLTableColElement;
    "data": HTMLDataElement;
    "datalist": HTMLDataListElement;
    "dd": HTMLElement;
    "del": HTMLModElement;
    "details": HTMLDetailsElement;
    "dfn": HTMLElement;
    "dialog": HTMLDialogElement;
    "dir": HTMLDirectoryElement;
    "div": HTMLDivElement;
    "dl": HTMLDListElement;
    "dt": HTMLElement;
    "em": HTMLElement;
    "embed": HTMLEmbedElement;
    "fieldset": HTMLFieldSetElement;
    "figcaption": HTMLElement;
    "figure": HTMLElement;
    "font": HTMLFontElement;
    "footer": HTMLElement;
    "form": HTMLFormElement;
    "frame": HTMLFrameElement;
    "frameset": HTMLFrameSetElement;
    "h1": HTMLHeadingElement;
    "h2": HTMLHeadingElement;
    "h3": HTMLHeadingElement;
    "h4": HTMLHeadingElement;
    "h5": HTMLHeadingElement;
    "h6": HTMLHeadingElement;
    "head": HTMLHeadElement;
    "header": HTMLElement;
    "hgroup": HTMLElement;
    "hr": HTMLHRElement;
    "html": HTMLHtmlElement;
    "i": HTMLElement;
    "iframe": HTMLIFrameElement;
    "img": HTMLImageElement;
    "input": HTMLInputElement;
    "ins": HTMLModElement;
    "kbd": HTMLElement;
    "label": HTMLLabelElement;
    "legend": HTMLLegendElement;
    "li": HTMLLIElement;
    "link": HTMLLinkElement;
    "main": HTMLElement;
    "map": HTMLMapElement;
    "mark": HTMLElement;
    "marquee": HTMLMarqueeElement;
    "menu": HTMLMenuElement;
    "meta": HTMLMetaElement;
    "meter": HTMLMeterElement;
    "nav": HTMLElement;
    "noscript": HTMLElement;
    "object": HTMLObjectElement;
    "ol": HTMLOListElement;
    "optgroup": HTMLOptGroupElement;
    "option": HTMLOptionElement;
    "output": HTMLOutputElement;
    "p": HTMLParagraphElement;
    "param": HTMLParamElement;
    "picture": HTMLPictureElement;
    "pre": HTMLPreElement;
    "progress": HTMLProgressElement;
    "q": HTMLQuoteElement;
    "rp": HTMLElement;
    "rt": HTMLElement;
    "ruby": HTMLElement;
    "s": HTMLElement;
    "samp": HTMLElement;
    "script": HTMLScriptElement;
    "section": HTMLElement;
    "select": HTMLSelectElement;
    "slot": HTMLSlotElement;
    "small": HTMLElement;
    "source": HTMLSourceElement;
    "span": HTMLSpanElement;
    "strong": HTMLElement;
    "style": HTMLStyleElement;
    "sub": HTMLElement;
    "summary": HTMLElement;
    "sup": HTMLElement;
    "table": HTMLTableElement;
    "tbody": HTMLTableSectionElement;
    "td": HTMLTableDataCellElement;
    "template": HTMLTemplateElement;
    "textarea": HTMLTextAreaElement;
    "tfoot": HTMLTableSectionElement;
    "th": HTMLTableHeaderCellElement;
    "thead": HTMLTableSectionElement;
    "time": HTMLTimeElement;
    "title": HTMLTitleElement;
    "tr": HTMLTableRowElement;
    "track": HTMLTrackElement;
    "u": HTMLElement;
    "ul": HTMLUListElement;
    "var": HTMLElement;
    "video": HTMLVideoElement;
    "wbr": HTMLElement;
}

class类

类的定义

必须提前声明属性和方法的类型

image.png

所以可以直接赋初始值,或者是调用 image.png

类修饰符

public:可以在外部通过变量直接调用,也可以在定义类的构造器或者方法里(即类内部)调用

private:只可以在当前类的内部调用

protect:可以在类内部和子类中访问

static 静态属性和方法 静态属性不可以通过this去调用,只能通过类名访问

image.png

静态函数不能访问其他变量,只能访问静态变量。类里面也不能通过this.静态方法调用,只能类名.静态方法

image.png

image.png

需要注意的是:两个静态方法可以相互通过this掉用,但也可以通过类名

image.png

抽象类

我们B类实现了A定义的抽象方法 如不实现就不报错 我们定义的抽象方法必须在派生类实现

image.png

元组

元组就是数组的变种,js中数组可以存放任意数据类型的数据,ts中数组只能存放特定类型的数据。因此如果想要存放不同类型的数据到数组里,就创造了元组 let arr: [number, string] = [12, '112']

它会被推断成一个联合类型

![image.png](p1-juejin.byteimg.com/tos-cn-i-k3…

枚举 enum

枚举是自增长型的,注意,如果只有Red赋值为1,后面就是23 image.png

image.png

类型别名 type

可以给一个类型定义一个名字,多用于复合类型

type和interface区别

相同点:都可以用于定义对象的类型。 不同点:①interface可以继承,type只能通过&交叉类型进行合并②interface遇到重名的会合并,type不可以③type可以使用操作符如| &等

never类型

常用于 switch


interface A {
    type: "foo"
}
 
interface B {
    type: "bar"
}
type All = A | B ;
function handleValue(val: All) {
    switch (val.type) {
        case 'foo':
            break;
        case 'bar':
            break
        default:
            //兜底逻辑 一般是不会进入这儿如果进来了就是程序异常了         
            const exhaustiveCheck:never = val;
            break
    }

Symbol

symbol类型的值是通过Symbol构造函数创建的 只支持传入number和string for in是不会循环symbol类型的属性

迭代器函数:通过next.done是否为false判断是否结束,如果为true,则结束循环

//迭代器函数  这其实就是for of的原理
let set: Set<number> = new Set([1, 2, 3, 4, 5])
type MapKeys = string | number
let map: Map<MapKeys, MapKeys> = new Map()
map.set('1', '网页')
map.set('2', '往上')

function generation(erg: any) {
  let it: Iterator<any> = erg[Symbol.iterator]()
  let next: any = { done: false }
  while (!next.done) {
    //如果next中没结束,就一直循环
    next = it.next()
    if (!next.done) {
      console.log(next)
     
    }
  }
}
generation(map)

for of 和for in区别

for in 循环数组,i输出的是索引,for of 是输出的值 遍历对象的时候 for in 是属性 of是value

泛型

语法:函数名字后面<参数名>,当使用这个函数的时候把参数的类型传递进去即可

定义时,不明确类型,使用时再确定唯一的类型

function add<T>(num1: T, num2: T): T[] {
  return [num1, num2]
}

//在使用时,必须明确类型
add<number>(1, 2)

定义了多个类型的泛型

function sub<T, U>(a: T, b: U): Array<T | U> {
  return [a, b]
}

sub<number, boolean>(1, false)
sub(2, '3')

泛型约束

image.png 解决办法:①通过类型断言 as

function getLength<T>(arg: T) {
  return (arg as string).length
}
console.log(getLength(1))

②定义泛型约束 即定义了一个接口,里面还有属性,让泛型来继承,这样传递的参数必须要有length属性才能传递 image.png

keyof 约束对象,这样如果返回对象没有的键值对就会报错

image.png

泛型类

//泛型类
class Sub<T> {
  attr: T[] = []
  constructor(num: T[]) {
    this.attr = num
  }
  public add(a: T): T[] {
    return [a]
  }
}

let s = new Sub<number>([1, 2, 3])
console.log(s.attr)

tsconfig.json 配置文件

include: 指定编译文件默认是编译当前目录下所有的ts文件

image.png

exclude: 排除某个文件,对某个文件不进行编译

target: js编译的版本 可以选择es2015 或者2016

outDir: 编译后文件输出目录

rootDir: 编译文件的目录

namespace 命名空间

ts和es2015一样,任何包含import或者export都被当成一个模块,相反的是,如果没有import和export 那么他的内容就被视为全局的。

image.png 解决办法:生成局部作用域 ①匿名函数②export 导出即可③namespace 其实它的原理就是用了匿名立即执行函数

image.png

三斜线指令

image.png

声明文件

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。

问题: image.png 解决办法: 1、npm i --save-dev @types/express 但是只有热门库才会有声明文件 2、自己定义 express.d.ts

装饰器 Decorator

必须在tsconfig.json中开启

image.png

类装饰器:就是将类的构造函数传入到watch参数

const watcher: ClassDecorator = (target: Function) => {
  target.prototype.getName = <T>(name: T): T => {
    return name
  }
}
@watcher
class A {
  constructor() {}
}
let a = new A()
console.log((a as any).getName('123124'))

装饰器工厂

//说白了就是外面再套一层函数,用高阶函数的方式传递参数
const watcher = (name: string): ClassDecorator => {
  return (target: Function) => {
    target.prototype.getParams = () => {
      return name
    }
  }
}

@watcher('zds')
class A {}

const a = new A()
console.log((a as any).getParams('123'))

rollup 搭建ts项目