前置涩话
掘金的小伙伴们大家好,这里是家里蹲选手sin~ 今天是重铸前端的第四天,今天就学习一下当下热门的TypeScript吧!首先来点ts基础,再收集一些知识点并记录一下吧。
✅ ts基础知识
为什么用TS?
1.ts是js的加强版,给js增加了可选的静态类型和面向对象编程。
2.ts是面向对象语言,包含类和接口的概念。
3.ts开发时就能给出编译错误,js运行时才能发现。
4.ts作为强类型语言,明确数据类型,代码可读性比较强。
5.ts可选链属性。
基础类型
let str:string = "大林忽悠"
let num:number = NaN
let bool:boolean = true
let sym:symbol = Symbol()
let n:null = null
let u:undefined = undefined
console.log(str)
any 任意类型 unknown 不知道的类型
类型等级:
1.any unknown top type 顶级类型
2.Object
3.Number String Boolean... 自身构造函数
4.number string boolean... 实例对象
5.1 '大林忽悠' false...
6.never
unknown只能赋值给自身或者any
unknown没有办法读任何属性,方法也不可以调用
unknown比any安全
//Object 和 object
//Object可以任意赋值
//object常用于类型约束,除了原始类型外的引用类型
let a:{} = {num: 1} //new Object 无法对变量进行任何赋值操作
数组
数组普通类型
let arr:number[] = [1,2,3]
let arr:boolean[] = [true,false]
let arr:Array = [true,false]
对象数组
interface X {
name:string
age?:number
}
let arr:X[] = [{name: "大林忽悠"}]
二维数组
let array:number[][] = [[1],[2],[3]]
let array:Array<Array> = [[1],[2],[3]]
杂烩数组
let array:any[] = [1,'asd',true,{}]
function fn2(...args:any[]) {
let a:IArguments = arguments //定义类数组
console.log(args)
}
fn2(1,2,3)
Symbol
for会全局寻找有没有注册过这个key,有直接用,没有就创建
Symbol.for('lin') === Symbol.for('lin') true
迭代器 [Symbol.iterator]
迭代器语法糖 for of
解构 数组解构底层原理是迭代器 对象不是
函数
1.函数定义类型和返回值 | 箭头函数定义类型和返回值
2.函数默认参数 | 函数可选参数
3.参数是一个对象如何定义
4.函数this类型
5.函数重载
// function add(a:number = 10,b?:number):number { 默认值和可选
// return a + b
// }
const add = (a:number,b:number):number => a+b
interface User {
name:string
age?:number
}
function P(user:User):User {
return user
}
console.log(P({name: '大林忽悠',age: 25}))
interface Obj {
user:number[]
add:(this:Obj,num:number)=>void
}
//ts可以定义this类型 必须是第一个参数定义this的类型
let obj:Obj = {
user:[1,2,3],
add(this:Obj,num:number) {
this.user.push(num)
}
}
obj.add(4)
console.log(obj)
函数重载,根据参数不同重载不同函数返回不同结果
let user:number[] = [1,2,3]
function findNum(add:number[]):number[]
function findNum(id:number[]):number[]
function findNum():number[]
function findNum(ids?:number[] | number[]):number[] {
if(typeof ids == 'number') {
return user.filter(v=>v == ids)
}else if (Array.isArray(ids)){
user.push(...ids)
return user
}else {
return user
}
}
元组:规定了数量,对应位置对应类型
let arr2:[number,boolean] = [1,false]
枚举类型 (数字枚举 字符串枚举 异构枚举 接口枚举 const枚举 反向映射)
enum Color { //red = 0, green = 1, blue = 2
red = 1, //red = 1, green = 2, blue = 3 增长枚举
green,
blue
}
enum Types {
success
}
let success:number = Types.success
let key = Types[success]
console.log(`value---${success}`,`key---${key}`)
类型断言
a as string <string>a
内置对象
//let num:Number = new Number(1)
let date:Date = new Date()
let reg:RegExp = new RegExp(/\w/)
//let div = document.querySelector('footer') as Element
//let div:NodeList = document.querySelectorAll('footer')
let div:NodeListOf<HTMLDivElement | HTMLElement> = document.querySelectorAll('div')
let local:Storage = localStorage
let lo:Location = location
let promise:Promise = new Promise((r)=>r(1))
let cookie:string = document.cookie
联合类型
联合类型使用 | 操作符表示允许一个值可以是多种类型中的一种。它表示“或”的关系,即一个变量可以是类型A或类型B
let value:number | string
value = 26
value = '大林'
交叉类型
交叉类型使用 & 符号将多个类型合并成一个新类型,这个新类型同时拥有所有输入类型的属性和方法。它表示“与”的关系,即一个对象同时满足多个类型的条件。
interface People{
name:string
age:number
}
interface Man{
sex:number
}
const dalin = (man:People & Man):void => {
console.log(man)
}
dalin({
name: '大林忽悠',
age: 25,
sex: 1
})
class
1.class的基本用法 继承(extends) 和 类型约束(implements)
2.class的修饰符 readonly(不可修改,只读) private(私有属性) protected(可继承私有) public
3.super原理
4.静态方法(static),只能通过类去调用
5.get set
虚拟dom 简单版
interface Options {
el:string | HTMLElement
}
interface VueCls {
options:Options
init():void
}
interface Vnode {
tag:string
text?:string
children?:Vnode[]
}
class Dom {
//创建节点的方法
private createElement(el:string) {
return document.createElement(el)
}
//填充文本的方法
private setText (el:HTMLElement, text:string | null) {
el.textContent = text
}
//渲染函数
protected render(data:Vnode) {
let root = this.createElement(data.tag)
if(data.children && Array.isArray(data.children)) {
data.children.forEach(item => {
let child = this.render(item)
root.appendChild(child)
})
} else {
data.text && this.setText(root, data.text)
}
return root
}
}
class Vue extends Dom implements VueCls{
options: Options
constructor (options: Options) {
super() //父类的prototype.constructor.call
this.options = options
this.init()
}
public init(): void {
let data:Vnode = {
tag: "div",
children: [
{
tag: "section",
text: "我是子节点1"
},
{
tag: "section",
text: "我是子节点2"
},
]
}
let app = typeof this.options.el == 'string' ? document.querySelector(this.options.el) : this.options.el
app && app.appendChild(this.render(data))
}
}
new Vue({
el: "#app"
})
基类 抽象类
abstract所定义的类
abstract所定义的方法都只能描述不能进行实现
抽象类无法实例化但可以被派生类继承
abstract class King {
name:string
constructor (name?:string) {
this.name = name
}
getName ():string{
return this.name
}
abstract init(name:string):void
}
class Lin extends King{
constructor () {
super()
}
init (name:string) {
}
setName (name:string) {
this.name = name
}
}
const lin = new Lin()
lin.setName('大林忽悠')
console.log(lin.getName())
interface接口
interface 重名的会进行重合
interface 任意key [propName:strng]:any (索引签名)
interface ?操作符(可选值) readonly(让值不可更改)
interface 接口继承 extends
interface 定义函数类型
不能多属性,也不能少属性
interface Axxsxs{
name:string
age?:number
readonly cb:()=>boolean
}
let x:Axxsxs = {
name: '大林忽悠',
age: 25,
cb:()=>{
return false
}
}
interface Fn {
(name:string):number[]
}
const fn:Fn = function (name:string) {
return [1]
}
type类型别名
与interface的区别:
1.不能用extends去继承(只能用交叉类型 & )
2.可以用联合类型 | ,interface不可以
3.interface重名合并,type不会
type s = number[] | string
let str1:s = '大林忽悠'
extends 在 types 是包含的意思(左边的值会作为右边类型的子类型)
type num = 1 extends number ? 1 : 0
implements 和 extends 的用法与区别
extends 继承
用途:
- 类继承类:子类继承父类的属性和方法(单继承)。
- 接口继承接口:合并多个接口的定义(多继承)。
- 类继承抽象类:继承抽象类的部分实现并强制重写抽象方法。
特点:
- 子类获得父类的实现代码(方法体、属性值)。
- 支持方法重写(
override)和通过super调用父类方法。 - 接口继承仅合并类型定义,无运行时代码 。
implements 实现
用途:
- 类实现接口:强制类实现接口中定义的所有属性和方法。
- 类可实现多个接口(多继承契约)。
interface Alarm { alert(): void }
interface Light { switch(): void }
// 类实现多个接口
class Car implements Alarm, Light {
alert() { /* 实现 */ }
switch() { /* 实现 */ }
特点:
- 仅类型约束,不继承任何实现代码。
- 接口可定义方法签名和属性类型,但不提供具体逻辑。
- 若未实现接口成员,会触发编译错误 。
泛型 <T,K>
泛型约束
keyof 把对象的key推断成联合类型 如下面obj1变成 name | sex
function lin1(a:T,b:T):Array{
return [a,b]
}
let obj1 = { name: '大林忽悠', sex: '男' }
type Key = keyof typeof obj1
function ob<T extends object,K extends keyof T>(obj:T,key:K){ return obj[key] }
ob(obj1, 'name')
高级用法 Partial
interface Data {
name:string
age:number
sex:string
}
//for (let key in obj)
type Options1 = {
readonly [key in keyof T]:T[key]
}
type B = Options1
//配置文件tsconfig.json
//namespace
//声明文件 d.ts
//Mixins混入
1.类装饰器 ClassDecorator target 构造函数
2.属性装饰器 PropertyDecorator
3.参数装饰器 ParameterDecorator
4.方法装饰器 MethodDecorator PropertyDescriptor
5.装饰器工厂
6.import 'reflect-metadata'
7.axios
const Base = (name:string) => {
const fn:ClassDecorator = (target) => {
console.log(target)
target.prototype.lin = name //给Http构造函数增加属性
target.prototype.fn = () => { //给Http构造函数增加方法
console.log('hello')
}
}
return fn
}
const Get = (url:string) => {
const fn:MethodDecorator = (target,_key,descriptor:PropertyDescriptor) => {
// const key = Reflect.getMetadata('key',target)
// axios.get(url).then(res=>{
// descriptor.value(key ? res.data[key] : res.data)
// })
}
return fn
}
const Result = () => {
const fn:ParameterDecorator = (target,key,index) => {
// Reflect.defineMetadata('key','result',target)
}
return fn
}
const Name:PropertyDecorator = (target,key) => {
}
@Base('大林忽悠') //装饰器工厂 闭包 函数柯里化
class Http {
//...
@Name
lin:string
constructor () {
this.lin = '大林忽悠'
}
@Get('https://api...')
getList (@Result() data:any) {
// console.log(data.result.list)
console.log(data)
}
}
const http = new Http() as any
console.log(http.lin)
//Paritial 把某个类型里的属性全部变成可选项
//Required 把某个类型里的属性全部变成必选项
//Readonly 把属性变成只读
//Record<T,K> 将K中所有属性的值转化为T类型
interface PageInfo{
title:string
}
type page = 'a'|'b'|'c'
type mix = Record<PageInfo, page>
const xx:mix = {
'a':{title:'xxx'},
'b':{title:'xxx'},
'c':{title:'xxx'}
}
//Exclude<T,U> 将其中某个类型中属于另一个类型的去掉。
type aa = Exclude<'a'|'b'|'c','a'> //只剩下'b'|'c'
type bb = Exclude<'a'|'b'|'c','a'|'b'> //只剩下'c'
//Extract<T,U>将t,u中的交集提取出来
问题:如何基于一个已有类型,扩展出大部分内容相似,但有部分区别的类型?
通过Pick和Omit
interface test {
name:string,
sex:string,
height:number
}
type Sex = Pick<test, 'sex'>
const aaa:Sex = {sex:'女'}
type WithoutSex = Omit<test, 'sex'>
const b:WithoutSex = {name: '11',height: 160}
ts实现简单发布订阅模式
//发布订阅模式
interface I {
events:Map<string,Function[]>
once:(event:string, callback:Function)=>void //触发一次
on:(event:string, callback:Function)=>void //订阅
emit:(event:string, ...args:any[])=>void //派发
off:(event:string, callback:Function)=>void //移除
}
class Emitter implements I {
events: Map<string, Function[]>
constructor () {
this.events = new Map()
}
once (event:string, callback:Function) {
//1.创建一个自定义函数,通过on触发一次,触发完就off掉
const cb = (...args:any[]) => {
callback(...args)
this.off(event, cb)
}
this.on(event, cb)
}
on (event:string, callback:Function) {
if (this.events.has(event)) {
//事件存过了
const callbackList = this.events.get(event)
callbackList && callbackList.push(callback)
} else {
//事件第一次存
this.events.set(event,[callback])
}
}
emit (event:string, ...args:any[]) {
const callbackList = this.events.get(event)
if (callbackList) {
callbackList.forEach(fn => {
fn(...args)
});
}
}
off (event:string, callback:Function) {
const callbackList = this.events.get(event)
if (callbackList) {
callbackList.splice(callbackList.findIndex(callback), 1)
}
}
}
const bus = new Emitter()
bus.on('message', (b:boolean, n:number)=>{
})
bus.emit('message', false, 1)