TypeScript学习

TypeScript学习

  1. ts基础类型:string、number、boolean、any、unknown(只能作为父类,赋值只能给any、unknown两种类型)、null、undefined、void
  2. 接口interface限制类型,使用了任意类型[propName: string]: any;,那么确定属性和可选属性的类型都必须是它的类型的子集。即整个接口里若任意类型为string,那么整个接口的类型都为string
  3. 类型断言写法:(num).length (num as string).length
    any可以断言为任何类型,用any来做临时断言
  4. 交叉类型使用&符号将多个接口连接
  5. 内置对象:Boolean、Number、string、RegExp、Date、Error
  6. DOM和BOM上的对象:Document、HTMLElement、Event、NodeList
//读取div 这种需要类型断言 或者加个判断应为读不到返回null
let div:HTMLElement = document.querySelector('div') as HTMLDivElement
  1. Promise 如果我们不指定返回的类型TS是推断不出来返回的是什么类型
  2. ts类型定义在源码的src/lib文件夹下
  3. 类中的静态成员只能供静态方法访问使用,静态方法中访问不到public、protected、private修饰的变量。静态方法可以调用其他静态方法。
  4. never类型:表示不应该存在的状态
应用场景:
// 只会抛出异常没有返回值
function Never():never {
   throw new Error('aaa')
}

// 因为存在死循环,所以 loop 将不会有返回值
function loop(): never {
   while (true) {
    }
}
// 在兜底逻辑里定义一个never变量,接口c如果不在函数中定义逻辑那一定会走default出口,因为never类型只能作为父类型,不能让子类型给他赋值,所有在编译会报错。
interface A {
    type: "foo"
}
interface B {
    type: "bar"
}
interface C {
    type: "bizz"
}
type All = A | B | C;
function handleValue(val: All) {
    switch (val.type) {
        case 'foo':
            break;
        case 'bar':
            break
        default:
            //兜底逻辑 一般是不会进入这儿如果进来了就是程序异常了
            const exhaustiveCheck: never = val;
            break
    }
}
  1. symbol类型:可以传递参做为唯一标识 只支持 string 和 number类型的参数。常用于作为对象的key值。

使用symbol定义对象的属性,不能通过一下四种方式拿到:

  1. for in 遍历
  2. Object.keys(对象名) 遍历
  3. Object.getOwnPropertyNames(对象名)
  4. JSON.stringify(对象名)

获取symbol定义的属性的方法:

  1. Object.getOwnPropertySymbols(对象名)//拿到具体的symbol 属性,对象中有几个就会拿到几个(只拿symbol类型的)
  2. Reflect.ownKeys(对象名)// 拿到对象的所有属性
  1. Symbol.iterator 迭代器:支持遍历大部分类型迭代器 arr、nodeList、argumetns、set 、map等。
let arr: Array<number> = [4, 4, 5]
let it: Iterator<number> = arr[Symbol.iterator]()
console.log(it.next()) // 输出第一个元素4
console.log(it.next())// 输出第二个元素4
console.log(it.next())// 输出第三个元素5
console.log(it.next()) //输出undefined

输出结果:

{ value: 4, done: false }
{ value: 4, done: false }
{ value: 5, done: false }
{ value: undefined, done: true }
value表示值,done表示是否不能迭代了,true表示后面没有值了,已经结束了
  1. 生成器for of 在js底层已经帮我们完成了迭代功能,使用的是iterator,所以for of不支持遍历对象。因为对象上没有Symbol.iterator 迭代器。

for of底层代码基础版封装:

const gen = (erg:any): void => {
    let it: Iterator<any> = erg[Symbol.iterator]()
    let next:any= { done: false }
    while (!next.done) {
        next =  it.next()
        if (!next.done) {
            console.log(next.value)
        }
    }
}
  1. for in和for of的区别:

(1)for in既能遍历对象也能遍历数组;for of不能遍历对象

(2)for in遍历数组时的key是数组的索引;for of是数组的那个值

  1. 泛型:语法为函数名字后面跟一个<参数名> 参数名可以随便写 例如我这儿写了T。当我们使用这个函数的时候把参数的类型传进去就可以了 (也就是动态类型)

  2. 泛型约束:对使用的泛型进行约束,我们约束其为具有length属性的类型。

interface Len {
   length:number
}
function getLegnth<T extends Len>(arg:T) {
  return arg.length
}
getLegnth<string>('123')
  1. 使用keyof 约束对象:首先定义了T类型并使用extends关键字继承object类型的子类型,然后使用keyof操作符获取T类型的所有键,它的返回类型是联合类型,最后利用extends关键字约束 K类型必须为keyof T联合类型的子类型。
// 在这个例子中:T:let o : { a: number,  b: number, c: number}
// K:就是T中对象的所有key值组成的联合类型,即a|b|c
function prop<T, K extends keyof T>(obj: T, key: K) {
   return obj[key]
}
let o = { a: 1, b: 2, c: 3 }
prop(o, 'a') 
  1. 泛型类:声明方法跟函数类似名称后面定义<类型>。
    定义时: 类名 // 这里T可以为任意名字,就是一个泛型的意思
    实例化时:new 类名<具体类型>

  2. 三斜线指令:/// 指令是三斜线指令中最常见的一种。
    它用于声明文件间的依赖。它可以告诉编译器在编译过程中要引入的额外的文件。
    引入声明文件:/// 引入到声明文件,表明这个文件使用了 @types/node/index.d.ts里面声明的名字; 并且,这个包需要在编译阶段与声明文件一起被包含进来。 仅当在你需要写一个d.ts文件时才使用这个指令。
    如果是下载的引入声明文件回去node_modules里去找@types/node/index.d.ts

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

declare var 声明全局变量
declare function 声明全局方法
declare class 声明全局类
declare enum 声明全局枚举类型
declare namespace 声明(含有子属性的)全局对象
interface  type 声明全局类型
/// <reference /> 三斜线指令

在引入第三方模块时,如果第三方包没有声明文件会出现红色下划线。
查看第三方包的声明文件:找到node_modules下第三方包的文件夹,找到package.json文件在types配置中会定义这个包的声明文件。
如果第三方包没有声明文件,需要我们自己定义。
定义方式:(1)在项目根目录下创建一个文件,文件名为第三方包名.d.ts
(2)在文件中写入一下代码
以express为例:declare  const express: ()=> any;
第三方声明文件的包查看在这个网址https://www.npmjs.com/~types?activeTab=packages

  1. mixins混入:可以把他看作为合并
    (1)对象混入:可以使用es6的Object.assign(对象1,对象2,…) 合并多个对象
    (2)类混入:使用implements, 把类当成了接口。
    混入类的理解:就是很多个已经写好的类,现在需要定义一个新类,需要之前定义好的类上的方法,实现整合(合并)。这个新类通过implements关键字实现之前定义好的类,在新类中定义好所有属性和方法的占位符。通过自己定义一个mixin函数实现将其他类的属性方法都放在新类中。
// A、B已经定义好的类
class A {
    type: boolean = false;
    changeType() {
        this.type = !this.type
    }
}
class B {
    name: string = '张三';
    getName(): string {
        return this.name;
    }
}
// C类需要A、B类上的所有方法和属性
// C类在这里提前写好占位符,通过自定义一个函数实现各属性和方法
class C implements A,B{
    type:boolean
    changeType:()=>void;
    name: string;
    getName:()=> string
}
Mixins(C, [A, B])
// Object.getOwnPropertyNames()可以获取对象自身的属性,除去他继承来的属性,对它所有的属性遍历,它是一个数组,遍历一下它所有的属性名
function Mixins(curCls: any, itemCls: any[]) {
    itemCls.forEach(item => {
        Object.getOwnPropertyNames(item.prototype).forEach(name => {
            curCls.prototype[name] = item.prototype[name]
        })
    })
}
  1. 装饰器:一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上。通过@函数名使用
    若要启用实验性的装饰器特性,你必须在命令行或tsconfig.json里启用编译器选项"experimentalDecorators": true,
    装饰器类型:ClassDecorator 、MethodDecorator、PropertyDecorator、ParameterDecorator

  2. rollup构建ts项目:
    (1)创建rollup.config.js文件
    (2)下载依赖:1.全局安装rollup npm install rollup-g
    2.安装TypeScript npm install typescript -D
    3.安装TypeScript 转换器 npm install rollup-plugin-typescript2 -D
    4安装代码压缩插件 npm install rollup-plugin-terser -D
    5 安装rollupweb服务 npm install rollup-plugin-serve -D
    6 安装热更新 npm install rollup-plugin-livereload -D
    7引入外部依赖 npm install rollup-plugin-node-resolve -D
    8安装配置环境变量用来区分本地和生产 npm install cross-env -D
    9替换环境变量给浏览器使用 npm install rollup-plugin-replace -D
    (3)配置rollup.config.js文件

  3. webpack构建ts项目:
    (1)创建配置文件webpack.config.js
    (2)安装依赖:安装webpack npm install webpack -D
    webpack4以上需要 npm install webpack-cli -D
    编译TS npm install ts-loader -D
    TS环境 npm install typescript -D
    热更新服务 npm install webpack-dev-server -D
    HTML模板 npm install html-webpack-plugin -D

  4. proxy和reflect实现数据:
    proxy函数有两个参数(target目标对象,handler{get函数,set函数})
    get函数读取操作的捕捉器。有三个参数(target目标对象,prop对象上的某个属性,receiver和target的值一样)
    set函数设置操作的捕捉器。有四个参数(target目标对象,prop对象上的某个属性,value修改的值,receiver和target的值一样(目的为了防止上下文错误))
    Reflect的所有属性和方法都是静态的。
    Reflect.get(target, name, receiver) //查找并返回target对象的name属性,如果没有该属性返回undefined
    Reflect.set(target, name,value, receiver) //设置target对象的name属性等于value

  5. Partial & Pick:TS内置的高级类型
    (1)Partial将泛型变量T中的所有属性设置为可选

// 源码实现:
type Partial<T> = {
     [P in keyof T]?: T[P];
}
// 理解:keyof将T中所有属性变为联合类型,in遍历这个联合类型中的每一项,即遍历了这个对象上所有的属性,将其变为可选的。T[P] 索引访问操作符,与 JavaScript 种访问属性值的操作类似,下面案例中的T[P]为string或者number。
例子:
type Person = {
   name:string,
   age:number
}
type p = Partial<Person>
理解:将Person这个类型中的属性都变为可选的,使用了Partial之后变为p变为:
type p = {
    name ?: string,
    age?: number
}2)Pick:从类型定义T的属性中,选取指定一组属性,返回一个新的类型定义。
源码实现:
type Pick<T, K extends keyof T> = {
       [P in K]: T[P];
}
// 理解:讲一个类型中部分属性取出来组成一个新的类型,就是过滤出来我们需要的属性
例子:
type Person = {
name:string,
age:number,
text:string
address:string
}
type Ex = "text" | "age"
type A = Pick<Person,Ex>
// 理解:就是把原先Person中的text和age属性过滤出来组件新类型A
  1. Record & Readonly:
    (1)Readonly:将该属性变为只读,将每一个属性变成只读
源码实现:
type Readonly<T> = {
       readonly [P in keyof T]: T[P];
};

(2)Record:做到了约束 对象的key 同时约束了 value

源码实现:
type Record<K extends keyof any, T> = {
          [P in K]: T;
}
// 理解:keyof any 返回 string number symbol 的联合类型;说明key只能传 string number symbol 这三种类型的变量,value就是你传来什么类型,所有属性都要符合这个类型。对key和value都做了约束。
  1. infer:ts新增到的关键字 充当占位符
    (1)infer一般用于类型约束extends后面
    (2)限制元祖的数据类型:
type TupleToUni<T> = T extends Array<infer E> ? E : never
type TTuple = [string, number];
type ToUnion = TupleToUni<TTuple>; // string | number
提取头部元素
type Arr = ['a','b','c'] //这个值是用来限制元素是什么类型的
type First<T extends any[]> =  T extends [infer First,...any[]] ? First : []
type a = First<Arr>
let num: a = 'a'
// 理解:本案例中提取a类型,且a类型的值只能为a
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hoki802

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值