ts学习 基本篇(类型) 01 - ts基本类型
类型
例子
描述
number
1, -33, 2.5
任意数字
string
‘hi’, “hi”,
任意字符串
boolean
true、false
布尔值true或false
字面量
其本身
限制变量的值就是该字面量的值
any
*
任意类型
unknown
*
类型安全的any
void
空值(undefined)
没有值(或undefined)
never
没有值
不能是任何值
object
{name:’孙悟空’}
任意的JS对象
array
[1,2,3]
任意JS数组
tuple
[4,5]
元素,TS新增类型,固定长度数组
enum
enum{A, B}
枚举,TS中新增类型
number类型
let decimal :number = 6 ; let hex :number = 0xf00d let binary :number = 0b1010 let octal :number = 0o744 let big :number = 100n
let isDone :boolean = true let isDone1 :boolean = false
let color :string = "blue" let fullName :string = `Bob ${color} `
字面量
使用具体的值来指定变量的类型或取值范围
let color :'red' |'blue' |'black' let num :1 |2 |3 |4 |5
any类型
let a :any = true a = 1 a = '1'
unknown类型
let notSure :unknown = 4 notSure = 'hello'
void类型
let unusable :void = undefined
never类型
function error (message:string ):never { throw new Error (message) }
object类型
let obj :object = {name :"pan" }
array类型
let list :number [] = [1 ,2 ,3 ]let list1 :Array <number > = [1 ,2 ,3 ]
tuple类型
let x :[string ,number ] = ['hello' ,1 ]
enum类型
enum Sex { mail = 1 , femail = 0 } const sex :Sex = Sex .mail enum FangXiang { top, right = 3 , bottom, left } console .log (FangXiang .right )
02 - 类型别名 type 定义 用于一些较长的类型,可以使用type来进行类型别名,避免代码定义类型冗余
type Num = 1 | 2 | 3 | 4 let num1 :Num = 1 num1 = 2
03 - interface 接口 定义 interface 和type 一样可以定义类型别名
interface Num { name :string , age :number } const formData :Num = { name :'pan' , age :18 }
04 - type和interface的区别
05 - 类型断言 当自动识别的类型不满足自己的需要时,可以使用类型断言来得到更准确的自己需要的类型
const canvasRrow = document .getElementById ("main_canvas" )const canvasRrow1 = document .getElementById ("main_canvas" ) as HtmlCanvasElement const canvasRrow1 = <HtmlCanvasElement >document .getElementById ("main_canvas" )
06 - 文字类型 文字类型使用于对数据进行只读操作,不能进行修改
const obj = { url :"https://www.baidu.com" , method :"GET" , } as const function request (url:string ,method:"GET" | "POST" | "PUT" ) { } request (obj.url ,obj.method )
07 - bigInt和symbol const a :bigint = BigInt (100 )const b :bigint = 100n const firstName = Symbol ('name' )const secondName = Symbol ('name' )
08 - typeof类型守卫 function sum (n:string | number ,input:string ){ if (typeof n === 'number' ){ return Array (n + 1 ).join (' ' ) + input }else { return n + input } } console .log (sum ("你好" ,'hello' ));
09 - 真值缩小 遇到 条件、&&、||、if语句、布尔否定(!)会产生真值缩小
function printAll (strs:string | string [] | null ): void { if (strs && typeof strs === 'object' ){ for (let str of strs){ console .log (str); } }else if (typeof strs === 'string' ){ console .log (strs); }else { } }
10 - 等值缩小 遇到 === 、!== 、== 、!= 的时候会产生等值缩小
function example (x :string | number ,y :string | boolean ){ if (x === y){ x = x.toUpperCase () y = y.toLowerCase () console .log (x,y); }else { console .log (x); console .log (y); } } example ("hello" ,"ello" );function example (x :string | number ,y :string | boolean ){ if (x === y){ x = x.toUpperCase () y = y.toLowerCase () console .log (x,y); }else { console .log (x); console .log (y); } } example ("hello" ,"ello" );function printAll (strs:string | string [] | null ){ if (strs !== null ){ if (typeof strs === 'object' ){ for (const x of strs){ console .log (x) } }else if (typeof strs === 'string' ){ console .log (strs) } } }
11 - in 操作符缩小 使用in操作符判断是否包含有
type Fish = { swim : () => void };type Bird = { fly : () => void };type man = { swim?: () => void , fly?: () => void }function move (animal: Fish | Bird | man ) { if ('swim' in animal) { return (animal as Fish ).swim (); } return (animal as Bird ).fly (); }
12 - instanceof 操作符缩小 使用instanceof操作符来进行判断 是否在原型链上来进行判断操作
function printAll (x :string | Date ){ if (x instanceof Date ){ console .log (x.toUTCString ()); } else { console .log (x.toUpperCase ()); } }
13 - 分配缩小 使用三目表达式来进行分配缩小
let x = Math .random () < 0.5 ?10 :'' x = 1 console .log (x);x = 'hello' console .log (x);
14 - 类型谓词 在函数返回值时进行判断是否为真还是假进行对应的返回类型
type Fish = { name :string , swim :()=> void } type Bird = { name :string , fly :()=> void } function isFish (pet:Fish|Bird ):pet is Fish { return (pet as Fish ).swim !== undefined } function getSmallPet ( ): Fish |Bird { let x :Fish = { name :'fish' , swim :()=> {} } let y :Bird = { name :'bird' , fly :()=> {} } return false ? y : x } const pet = getSmallPet ()if (isFish (pet)){ pet.swim () console .log ('真' ); }else { pet.fly () console .log ("假" ); }
15 - unions(联合类型) interface Square { type : 'square' ; sideLength :number } interface Rectangle { type : 'rectangle' ; radius :number } type Shape = Square | Rectangle ;function getArea (shape: Shape ){ switch (shape.type ){ case 'square' : return shape.sideLength ** 2 case 'rectangle' : return Math .PI * shape.radius ** 2 } }
16 - never 类型 使用范围,穷进行检查,来判断拓展接口进行错误提示
interface Square { type : 'square' ; sideLength :number } interface Rectangle { type : 'rectangle' ; radius :number } interface sanjiao { type : 'sanjiao' sideLength :number } type Shape = Square | Rectangle | sanjiao;function getArea (shape: Shape ){ switch (shape.type ){ case 'square' : return shape.sideLength ** 2 case 'rectangle' : return Math .PI * shape.radius ** 2 case 'sanjiao' : return shape.sideLength ** 2 default : const _qiong :never = shape; return _qiong; } }
基本篇(函数) 01 - 函数类型表达式 定义函数类型
type GrandeFunction = (n:string )=> void function handleFunction (fn:GrandeFunction ){ fn ('hello world' ) } function helloWorld (n:string ){ console .log (n); console .log ('hello world' ) } handleFunction (helloWorld)
02 - 调用签名 其实就是定义了一个函数,在函数身上定义了一个方法
type dirceFunction = { dirce :string , (str :string ):boolean } function handleDirce (fn:dirceFunction ){ console .log (fn.dirce + 'hello' ); } function handle1 ( ){ console .log ('handle1' ); return true ; } handle1.dirce = '我的' handleDirce (handle1)
03 - 构造签名 其实构造签名就是定义了一个类。
class Ctor { n :string constructor (n:string ){ this .n = n } } type constroller = { new (n :string ):Ctor } function handleConstroller (fn:constroller ){ const fn1 = new fn ('hello' ) console .log (fn1.n ); } handleConstroller (Ctor )interface DateFunc { new (n :string ):Date (s :number ):string } function handleFunc (func:DateFunc ){ const a = new func ("2024-1-8" ) const b = func (100 ) } handleFunc (Date )
04 - 泛型函数 04 - 1- 类型推断 使用场景,使用前不知道会使用什么类型,在使用时,类型之间想要产生关联就使用泛型。
function handleString<T>(arr :T[]):T{ return arr[0 ] } handleString ([1 ,2 ,3 ])function map<I,O>(arr :I[],func :(item:I )=> O):O[]{ return arr.map (func) } const parsed = map (["1" ,"2" ,"3" ],(item )=> parseInt (item))
04 - 2 - 限制条件 使用extends来继承祖代值,来进行限制类型
function longest<T extends {length :number }>(a :T,b :T):T{ if (a.length >b.length ){ return a }else { return b } } const res1 = longest ([1 ,2 ,3 ],[1 ,2 ])const res2 = longest ('abc' ,'ab' )const res3 = longest (100 ,10 )
04 -3 - 指定类型参数 当泛型需要不只一种可能性参数时使用
function handleTest<T>(a :T[],b :T[]):T[]{ return a.concat (b) } handleTest<string |number >([1 ,2 ,3 ],["1" ,"2" ,"3" ])
05 - 函数可选值 函数可选值为函数参数上加一个?来判断参数可选
function handleTest (n?:number ):undefined |string { if (!(n === undefined )) { return n.toFixed (3 ) }else { return undefined } } console .log (handleTest (10 ));console .log (handleTest ());
06 - 回调中的可选参数 在创建回调函数中,不要写可选值,避免错误出现!
function handleTest (arr:any [],callback:(value:any ,index?:number )=>void ){ for (let i=0 ;i<arr.length ;i++){ callback (arr[i]) } } handleTest ([1 ,2 ,3 ],(value,index )=> { console .log (index?.toFixed ()) })
07 - 函数重载 07 - 1 - 函数重载函数情况 使函数有多种传参方式,可以根据自己的参数要求来
注意:在写函数重载时,最后一个重载为前面所有函数参数的一个总和
function makeDate (timemap:number ):Date function makeDate (month:number ,day:number ,year:number ):Date function makeDate (mOrTimestamp:number ,d?:number ,y?:number ):Date { if (d!== undefined && y!== undefined ){ return new Date (y,mOrTimestamp,d) }else { return new Date (mOrTimestamp) } } const res1 = makeDate (100 )const res2 = makeDate (100 ,1 ) const res3 = makeDate (100 ,1 ,2020 )
注意:前两个函数叫做函数重载,叫做重载签名,后面一个叫做实现签名。实现签名要兼容前面的重载签名情况。
function handleTest (x:string ,y:number ):string function handleTest (x:number ,y:boolean ,z:string [] ):number function handleTest (x:string |number ,y:number | boolean ,z?:string [] ):string | number { if (typeof x === 'string' ){ return 'string' }else { return 10 } }
07 - 2 - 函数重载 - this interface User { admin :boolean } interface DB{ filterUser (filters :(this :User )=> boolean ):User [] } const db :DB ={ filterUser (filters:(this :User)=>boolean ){ let user1 :User = { admin :true } let user2 :User = { admin :false } return [user1,user2] } } const adminUsers = db.filterUser (function (this :User ){ return this .admin }) console .log (adminUsers);
08 - 展开运算符 08 -1- 展开运算符-形参展开 function handleBei (n:number ,...res:number [] ):number []{ return res.map (v => v*n) } handleBei (5 ,1 ,2 ,3 ,4 )
08 -2- 展开运算符-实参展开 const arr = [8 ,5 ] as const const angle = Math .atan2 (...arr)type Arr = [number ,number ]const arr1 :Arr = [5 ,6 ]const angle1 = Math .atan2 (...arr1)
09 - 参数解构(定义类型) interface ABC{ a :number b :number c :number } function sum ({a,b,c}:ABC ){ return a+b+c; } sum ({a :1 ,b :2 ,c :3 });
基础篇(对象) 01 - 对象类型 function handleObj0 (person: { name: string , age: number } ){ return person.name } interface Person1 { name : string , age : number } function handleObj1 (person: Person1 ){ return person.name } type Person2 = { name : string , age : number } function handleObj (person: Person2 ){ return person.name }
02 - 可选属性 interface Person { name :string , age?:number desc?:string } function showPerson ({name,age=0 ,desc='' }:Person ){ console .log (name,age,desc); } showPerson ({name :'张三' ,age :20 })showPerson ({name :'张三' ,age :20 ,desc :'学生' })
03 - 只读属性 注意:只读属性readonly只针对当前的属性进行只读操作,并不是对其内部有其内部的限制
interface ReadonlyPerson { readonly person :{ name :string age :number } } let persons :ReadonlyPerson = { person :{ name :"张三" , age :18 } } persons.person .age = 18 persons.person = {name :"李四" ,age :20 }
interface ReadonlyPerson { readonly name :string readonly age :number } interface Person { name :string age :number } let person :Person = {name :'张三' ,age :18 }let readonlyPerson :ReadonlyPerson = personperson.age ++ console .log (readonlyPerson.age );
04 - 索引签名 interface Person1 { [index :number ]:string ; } let person :Person1 = ['1' ,'2' ,'3' ]let person1 :Person1 = {0 :'1' ,1 :'2' ,2 :'3' }interface Person2 { [prop :string ]:string | number ; name :string length :number } let person2 :Person2 = { name :"张三" , length :18 , age :18 , desc :'' }
05 - 拓展类型 interface StudentBase { name :string age :number } interface Student extends StudentBase { grade :string } const student1 :Student = { name :"张三" , age :18 , grade :"一年级" } interface Circle { radius :number } interface Color { color :string } interface CircleColor extends Circle ,Color { name :string } let circleColor :CircleColor = { name :'circle' , radius :10 , color :'red' }
06 - 交叉类型 interface Circle { radius :number } interface Color { color :string } type CircleWithColor = Circle & Color function dorwCircle (dorw:CircleWithColor ){ console .log (dorw.color ); console .log (dorw.radius ); } dorwCircle ({radius :1 ,color :"blue" })
07 - 处理冲突(interface、type) interface Person { name :string } interface Person { age :number } const person :Person = { name :"张三" , age :30 } type Person1 = { name :string } type Person1 = { age :number }
08 - 泛型对象类型 使用泛型来对对象进行泛型约束
interface Person <T>{ contens :T } const res :Person <string > = { contens :"hello" } type Person1 <T> = { contens :T } const res1 :Person1 <string > = { contens :"hello" } type perOrNull<T> = T | null type perOrMany<T> = T | T[]type perOrManyOrNull<T> = perOrMany<T> & perOrNull<T>type perOrManyOrNull<T> = perOrNull<perOrMany<T>>
基础篇(泛型) 01 - helloWord开始篇章 function putUser<T>(a :T):T{ return a } const a = putUser<number >(1 )const b = putUser (1 )
02 - 使用通用类型变量 function handleloading<T>(arr :T[]):T[]{ console .log (arr.length ); return arr } handleloading<number >([1 ,2 ,3 ])
03 - 泛型类型 泛型类型就相当于给接口定义了泛型
interface GenericIdentityFn <T>{ (arg :T):T } function handleloading<T>(arr :T):T{ return arr } 这几种都等价 let myIdentity :GenericIdentityFn <string >=handleloading
04 - 泛型类 class Person <T>{ num : T; add :(x:T,y:T )=> T } let p = new Person <number >();p.num = 123 ; p.add = (a,b )=> a+b;
05 - 泛型约束 使用extends来进行对泛型进行约束
interface lengthwise { length : number ; } function printLength<T extends lengthwise>(x : T){ console .log (x.length ); } printLength ('10' )
06 - 在泛型约束中使用类型参数 这个keyof 表示K必须是在T的泛型中存在的,对应的是key值
function handleTest<T,K extends keyof T>(arr :T,key :K):T[K] { return arr[key]; } var obj = {a : 1 , b : 2 , c : 3 };console .log (handleTest (obj, "a" )); console .log (handleTest (obj, "b" )); console .log (handleTest (obj, "c" )); console .log (handleTest (obj, "d" ));
07 - 在泛型中使用类类型 class BeeKeeper { hasMask : boolean = true } class Zookeeper { nametag : string = "Mikle" } class Animal { numLegs : number = 4 } class Bee extends Animal { keeper : BeeKeeper = new BeeKeeper () } class Lion extends Animal { keeper : Zookeeper = new Zookeeper () } function create<T extends Animal >(c :new ()=>T):T{ return new c () } create (Lion )create (Bee )create (Animal )create (Zookeeper ) create (BeeKeeper )
基础篇(操作约束) 01 - keyof类型操作符 注意:使用keyof操作索引签名时候,会默认存在一个隐式的number类型
type Point0 = { x :number , y :number } type A = keyof Point0 const a :A = 'x' const b :A = 'y' type Point1 = { [n :number ]:unknown } type B = keyof Point1 const c :B = 1 const d :B = 2 type Point2 = { [n :string ]:unknown } type C = keyof Point2 const e :C = '1' const f :C = 1
02 - typeof 类型操作符 let a :number = 1 let b :typeof a = 2 function fn ( ){ return { x :1 , y :'1' } } type Fn = typeof fnconst fn1 :Fn = ()=> { return { x : 2312 , y : '123' } }
03 - 索引访问类型 type Person = { name : string ; age : number ; isStudent : boolean ; } type PersonChild = Person [keyof Person ]type NameOrAgePerson = 'age' | 'name' type I0 = Person [NameOrAgePerson ]const array = [ {name : '张三' , age : 18 , isStudent : true }, {name : '李四' , age : 20 , isStudent : false }, {name : '王五' , age : 22 , isStudent : true }, ] type arraytype1 = typeof array[number ]type arraytype2 = typeof array[number ]['age' ]
04 - 条件类型 interface Fish { siwm :boolean } interface Bird { fly :string } type HandleTest <T> = T extends {siwm :true } ? string : number type HandleTest2 = HandleTest <Fish > type HandleTest3 = HandleTest <Bird >
05 - 条件类型约束 interface Fish { siwm :boolean } interface Bird { fly :string } type HandleTest0 <T extends {siwm :unknown }> = T extends {siwm :true } ? string : number type HandleTest2 = HandleTest0 <Fish >type HandleTest3 = HandleTest0 <Bird > type HandleTest1 <T> = T extends any [] ? T[number ] : Ttype HandleTest4 = HandleTest1 <string []> type HandleTest5 = HandleTest1 <number []> type HandleTest6 = HandleTest1 <number >
06 - 在条件类型中进行推理 type HandleTest0 <T> = T extends (...agrs : never []) => infer Return ? Return : never ; type Num = HandleTest0 <()=> number > type Str = HandleTest0 <(x:string )=> string > type Bools = HandleTest0 <(a:boolean ,b:boolean )=> boolean > function handleTest (x: number ): string ;function handleTest (x: string ): number ;function handleTest (x: number | string ):string | number function handleTest (x: number | string ): string | number { return Math .random () > 0.5 ? "hello" : 1 ; } type Test = HandleTest0 <typeof handleTest>;
07 - 分布式条件类型 对于单个类型进行依次判断
type handleTest1<T> = T extends any ?T[]:never type handleTest2<T> = [T] extends [any ]?T[]:never type A = handleTest1<string | number | boolean >type B = handleTest2<string | number | boolean >
基础篇(类) 01 - 类成员 类成员分为:类属性、readonly、构造器、方法、Getters/Setters 、索引签名
02- 类属性 class Person { x :string y :number constructor (x:string ,y:number ){ this .x = x this .y = y } } let person = new Person ("1" ,1 )
03 - readonly属性 class Person { readonly x :string constructor (x:string ){ this .x = x } } let person = new Person ('你好' )console .log (person.x );person.x = '你好啊'
04 - 构造器 class Base { age :number constructor (age:number ) { this .age = age } } class Person extends Base { name :string constructor (name:string ,age:number ){ super (age) this .name = name } } const person = new Person ("张三" ,18 )
05 - 方法 class Base { age :number constructor (age:number ) { this .age = age } getAge ( ){ return this .age } } const person = new Base (18 )
06 - getters和setters访问器 class Base { _age :number = 0 get age ():number { return this ._age } set age (value:number | string | boolean ){ const num = Number (value) if (!Number .isFinite (num)){ this ._age = 0 return } this ._age = num } } const person = new Base ()person.age = '20' console .log (person.age )person.age = '20a' console .log (person.age );
07 - 索引签名 class Person { [k :string ]:string | ((s?:string )=> void ) name :string = 'pansida' getName ( ){ console .log (this .name ); } } const person = new Person ()person.getName ()
08 - 继承 implements子句 这个implements就是相当于定义class实体类时可以使用implements子句来进行给实体类定义类型
interface Person { name :string fn :(n:string )=> void } class HandleTest implements Person { name : string = 'pan' fn (n:string | number ){ if (typeof n === 'string' ){ console .log (n.length ) }else { console .log (n) } } }
09 - 继承 extends子句 class A { he ( ){ console .log ('A' ); } } class B extends A { worf (times:number ){ for (let index = 0 ; index < times; index++) { console .log ('B' ); } } } const c = new B ();c.he () c.worf (5 );
10 - 重写方法 class A { he ( ){ console .log ('A' ); } } class B extends A { he (times?:string ){ if (times === undefined ){ super .he (); }else { console .log ('B:' ,times); } } } const c = new B ();c.he () c.he ('render' );
11 - 初始化顺序 注意(初始化顺序) :
基类的字段被初始化
基类构造函数运行
派生类的字段被初始化
派生类构造函数运行
class A { name = 'A' constructor ( ){ console .log ('A中:' ,this .name ); } } class B extends A { name = 'B' constructor ( ){ super () console .log ('B中:' ,this .name ); } } const c = new B ();
12 - 继承内置类型 class MyError extends Error { constructor (message:string ){ super (message) this .message = message; } SayHello (){ console .log (this .message ); } } const myerror = new MyError ("Hello" );myerror.SayHello ();
13 - 成员的可见性-public class Person { public greet ( ){ console .log ("hi!" ); } } class Children extends Person { constructor ( ){ super () this .greet () } } const child = new Children ()child.greet ()
14 - 成员的可见性-protected class Person { public name = 'pan' protected SaiHello (){ console .log ("Hello" ); } } class Children extends Person { constructor ( ){ super () this .SaiHello () } } const child = new Children ()class M { protected name = 'pan:M' } class N extends M { public name = 'pan:N' } const test = new N ()console .log (test.name );
15 - 成员的可见性 - privide class Person { private name = 'pan' public SaiHello (){ console .log (this .name ); } } class Children extends Person { constructor ( ){ super () this .SaiHello () } } const child = new Children ()class A { private name = 'A' public getName (n:A ){ return n.name === this .name } } const a1 = new A ()const a2 = new A ()a1.getName (a2)
16 - 静态成员 注意:
特殊的静态名称不安全,避免使用:name、length、call等
Typescript中没有静态类的概念,因为js中还有函数和普通对象表示
class Person { static a = 1 protected static b = 1 static SayHello (){ console .log ('hi' ); } } class Children extends Person { constructor ( ){ super () console .log (Person .b ); } } Person .SayHello ();
17 - static区块 注意:static区块和constructor的区别:
static区块可以在实例没创建之前就可以调用,而constructor要在创建实例才调用
class Person { static #count = 0 ; get count (){ return Person .#count; } static { const lastInterce = {length :100 } Person .#count+=lastInterce.length } } const person = new Person ();console .log (person.count );
18 - 泛型类 class Box <T> { contents :T constructor (value:T ) { this .contents = value } static id :T } const box = new Box <string >('Hello World' )const box1 :Box <string > = new Box ('Hello World' )const box2 = new Box ('Hello World' )
19 - 类运行中的this class Box { name = 'Box' getName = ()=> { return this .name } getName ( ){ return this .name } } const box = new Box ()const obj = { name :'obj' , getName :box.getName } console .log (obj.getName ())
20 - this类型 class Box { content :string = '' sameAs (ohter:this ){ return ohter.content === this .content } } class DerivedBox extends Box { otherContent :string = '?' } const base = new Box ()const derived = new DerivedBox ()derived.sameAs (base)
21 - 基于类型守卫的this class FileSystemObject { isFile ():this is FileRep { return this instanceof FileRep ; } isDirectory ():this is Directory { return this instanceof Directory ; } isNetWorked ():this is NetWorked & this { return this .NetWorked } constructor (public path:string ,private NetWorked:boolean ){ } } class FileRep extends FileSystemObject { constructor (path:string ,public content:string ){ super (path,false ); } } class Directory extends FileSystemObject { children :FileSystemObject [] constructor ( ){ super ('' ,true ); this .children =[]; } } interface NetWorked { host :string } const fso :FileSystemObject = new FileRep ('/index.txt' ,'foo' )if (fso.isFile ()){ fso.content }else if (fso.isDirectory ()){ fso.children }else if (fso.isNetWorked ()){ fso.host } class Box <T>{ value?:T hasValue ():this is {value :T}{ return this .value !== undefined ; } } const box :Box <string > = new Box ()box.value = 'hello' if (box.hasValue ()){ console .log (box.value ); }
22 - 参数属性 class Person { constructor (public name:string ,protected age:number ,private gender:string ){ this .name =name; this .age =age; this .gender =gender; } }
23 - 类表达式 const someName = class <T>{ name :string constructor (value:string ){ this .name = value } } const n = new someName ('123' )console .log (n.name );
24 - 抽象类和成员 abstract class Base { abstract getName ():string SayHello (){ console .log (`Hello ${this .getName()} ` ); } } class Child extends Base { getName ( ){ return "Child" } } const child = new Child ()console .log (child.getName ());child.SayHello (); function HandleTest (Constor:new ()=>Base ){ const a = new Constor () console .log (a.getName ()); a.SayHello () } HandleTest (Child )
25 - 类之间的关系 class A1 { name :string ='pan' age :number = 18 } class A2 { name :string ='xiaopan' age :number = 20 } const a1 :A2 = new A1 ()class Test {} function fn (test:Test ){} fn (window )fn (document )fn (100 )
基础篇(小满扩展) 01 - Object、object、{}的区别 let a1 :Object = 1 let a2 :Object = "1" let a3 :Object = []let a4 :Object = {}let a5 :Object = new Date ()let a6 :Object = ()=> 12 let a :object ='123' let a1 :object = 123 let a2 :object = true let a3 :object =[]let a4 :object ={}let a5 :object =()=> 123 let a :{}='123' let a1 :{}= 123 let a2 :{}= true let a3 :{}=[]let a4 :{}={}let a5 :{}=()=> 123 let b :{} = {name :123 } b.age = 1
02 - 后端接口怎么定义 interface A{ name :string age :number [key :string ]:any } const res :A = { name :'xiaopan' , age :123 , f :0 } function handleTest (...agrs:number [] ){ const a :IArguments = arguments }
03 - 在对象中定义this interface A { user :string [], fn :(this :A,a:string )=> void } let res :A = { user :['pan' ,'xiao' ], fn (this :A,a:string ){ this .user .push (a) } } res.fn ("1" );
04 - 常用的一些的内置类型 let a :Number = new Number (1 )let b :String = new String ('hello' )let time :Date = new Date ()let regExp :RegExp = new RegExp ('\\w+' ) let error :Error = new Error ('Error occurred' )let xml :XMLHttpRequest = new XMLHttpRequest ()const dom = document .querySelector ('div' )const dom2 = document .querySelector ('footer' )const doms1 :NodeList = document .querySelectorAll ('div' )const doms2 :NodeListOf <HTMLDivElement | HTMLElement > = document .querySelectorAll ('header' )const local :Storage = localStorage const cookie :string = document .cookie const lo :Location = locationconst promise :Promise <string > = new Promise ((res )=> res ('done' ))
05 - vue简写版 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; } 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 { this .setText (root, data.text as string ); } return root } } class Vue extends Dom implements Vuecls { options : Options ; constructor (options: Options ){ super () this .options = options; this .init (); } init ():void { let data :Vnode = { tag :'div' , children :[ {tag :'div' ,text :'hello' }, {tag :'div' ,text :'world' } ] } let app = typeof this .options .el === 'string' ? document .querySelector (this .options .el ) : this .options .el ; app?.append (this .render (data)) } } new Vue ({ el :'#app' })
06 - const枚举 const enum Tyeps { success, fail } const res :number = 0 if (res === Tyeps .success ){} "use strict" ;const res = 0 ;if (res === 0 ) {} enum Tyeps { success, fail } const res :number = 0 if (res === Tyeps .success ){} "use strict" ;var Tyeps ;(function (Tyeps ) { Tyeps [Tyeps ["success" ] = 0 ] = "success" ; Tyeps [Tyeps ["fail" ] = 1 ] = "fail" ; })(Tyeps || (Tyeps = {})); const res = 0 ;if (res === Tyeps .success ) {}
07 - 反向映射枚举 enum Types { success= 2312 } const success = Types .success const type = Types [2312 ] console .log (`type:${type } ` ,`success:${success} ` );
08 - 类型层次
09 - Symbol类型 const num1 :symbol = Symbol ("1" ) const num2 :symbol = Symbol ("1" ) console .log (num1 === num2); console .log (Symbol .for ("1" ) === Symbol .for ("1" ));
10 - 迭代器/生成器 function * fn ( yield 1 yield 2 yield 3 yield 4 yield 5 ) let g = fn ()g.next () g.next () g.next () const set = new Set ([1 , 2 , 3 , 4 , 5 ,1 ,2 ,4 ]); const map = new Map () const obj = [1 ,2 ,3 ]map.set (obj,1 ) const each = (value:any )=>{ let It :any = value[Symbol .iterator ]() let next :any = {done :false } while (!next.done ){ next = It .next () if (!next.done ){ console .log (next.value ); } } } for (let i of obj){ console .log (i) } let [a,b,c] = [1 ,2 ,3 ]const obj3 = { max :5 , current :0 , [Symbol .iterator ](){ return { current :0 , max :this .max , next ( ){ if (this .current === this .max ){ return { value :undefined , done :true } }else { this .current ++; return { value :this .current , done :false } } } } } } for (let i of obj3){ console .log (i); }
11 - 泛型封装axios(简易版) const axios = { get<T>(url :string ):Promise <T>{ return new Promise ((resolve,reject )=> { let xml :XMLHttpRequest = new XMLHttpRequest () xml.open ('GET' ,url) xml.onreadystatechange = ()=> { if (xml.readyState === 4 && xml.status === 200 ){ resolve (JSON .parse (xml.responseText )) } } xml.send (null ) }) } } interface Data { message :string , code :number } axios.get <Data >('./db.json' ).then (res => { console .log (res); })
12 - keyof高级用法 interface Obj { name :string , age :number , dec :string } type Options <T extends Obj >= { [key in keyof T]?:T[key] } type B = Options <Obj >
13 - ts配置文件 "compilerOptions" : { "incremental" : true , "tsBuildInfoFile" : "./buildFile" , "diagnostics" : true , "target" : "ES5" , "module" : "CommonJS" , "outFile" : "./app.js" , "lib" : ["DOM" , "ES2015" , "ScriptHost" , "ES2019.Array" ], "allowJS" : true , "checkJs" : true , "outDir" : "./dist" , "rootDir" : "./" , "declaration" : true , "declarationDir" : "./file" , "emitDeclarationOnly" : true , "sourceMap" : true , "inlineSourceMap" : true , "declarationMap" : true , "typeRoots" : [], "types" : [], "removeComments" :true , "noEmit" : true , "noEmitOnError" : true , "noEmitHelpers" : true , "importHelpers" : true , "downlevelIteration" : true , "strict" : true , "alwaysStrict" : true , "noImplicitAny" : true , "strictNullChecks" : true , "strictFunctionTypes" : true , "strictPropertyInitialization" : true , "strictBindCallApply" : true , "noImplicitThis" : true , "noUnusedLocals" : true , "noUnusedParameters" : true , "noFallthroughCasesInSwitch" : true , "noImplicitReturns" : true , "esModuleInterop" : true , "allowUmdGlobalAccess" : true , "moduleResolution" : "node" , "baseUrl" : "./" , "paths" : { "jquery" : ["node_modules/jquery/dist/jquery.min.js" ] }, "rootDirs" : ["src" ,"out" ], "listEmittedFiles" : true , "listFiles" : true } "include" : [ "src/**/*" ], "exclude" : [ "demo.ts" ], "files" : [ "demo.ts" ]
14 - namespace命名空间 namespace ios { export let a = 1 } namespace android { export let b = 2 export namespace android_inter{ export let c = 3 } } console .log (ios.a );console .log (android.b );console .log (android.android_inter .c );
15 - 三斜线指令 namespace A{ export let a = 1 } namespace A { export let x = 1 ; export function f ( ) {} } console .log (A.a );
16 - 声明文件(包名.d.ts) 有一些第三方没有自己相对应的包名声明文件。以下为解决方案:
使用社区提供的声明文件进行下载,下载
@types/包名 // 例如:@types/node
下载404使用第二种方法,进行手动编写声明文件
declare module '包名' { exprots default 导出内容 }
以下为一个以express的实例
declare module 'express' { interface App { use :(path:string ,router:Router )=> void listen :(port:number ,cb:()=>void )=> void } interface Router { get (path :string ,cb :(req:any ,res:any )=> void ):void } interface Express { ():App , Router ():Router } const express : Express ; export default express }
17 - Mixin混入
将多个类或对象等混入在一起
interface A { name :string } interface B { age :number fn :()=> void dec :Dec } type Dec = [number ,number ,{name :string }]const res1 :A = { name :'pan' } const res2 :B = { age :18 , fn :()=> {console .log ('fn' )}, dec :[1 ,2 ,{ name :'pan' , }] } const res3 = {...res1,...res2}const res4 = Object .assign ({},res1,res2)const a = structuredClone (res1)
class logger { log (msg:string ){ console .log (msg); } } class Html { render (res:string ){ console .log (res); } } class App { run ( ){ console .log ("run" ); } } type Constructor <T> = new (...args : any []) => T;function Mixins <T extends Constructor <App >>(Base :T){ return class extends Base { private logger :logger; private html :Html ; constructor (...args: any [] ){ super (...args) this .logger = new logger (); this .html = new Html (); } run (): void { this .logger .log ('hello' ) } render ( ){ this .logger .log ('hello' ) this .html .render ('<h1>hello</h1>' ); } } } const mixins = Mixins (App )const app = new mixins ()app.run () app.render ()
18 - 装饰器(Decorator) 类装饰器(ClassDecorator) 就是对class类进行拓展修饰
const Base :ClassDecorator = (target )=> { target.prototype .name = '123' ; target.prototype .fn = ()=> { console .log ('fn' ); } } @Base class Http { } const Base = (str: string ) => { const fn : ClassDecorator = (target ) => { target.prototype .name = "123" ; target.prototype .fn = () => { console .log ("fn" ,str); }; }; return fn; }; @Base ("pan" )class Http {}
方法装饰器 (MethodDecorator) 就是对类中方法进行修饰
import axios from 'axios' ;const Get = (url:string )=>{ const fn :MethodDecorator = (target,key,descriptor:PropertyDescriptor )=> { axios.get (url).then (res => { descriptor.value (res.data ) }) } return fn } class Http { @Get ('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10' ) getList (data:any ){ console .log (data); } }
参数装饰器(ParameterDecorator) 对参数进行修饰
import 'reflect-metadata' import axios from 'axios' ;const Get = (url:string )=>{ const fn :MethodDecorator = (target,key,descriptor:PropertyDescriptor )=> { const key1 = Reflect .getMetadata ('key' ,target) axios.get (url).then (res => { descriptor.value (key1?res.data [key1]:res.data ) }) } return fn } const Result = ( )=>{ const fn :ParameterDecorator = (target,key,index )=> { console .log (target,key,index); Reflect .defineMetadata ('key' ,"result" ,target) } return fn } class Http { @Get ('https://api.apiopen.top/api/getHaoKanVideo?page=0&size=10' ) getList (@Result () data:any ){ console .log (data); } }
基础篇(构建TS项目) 01 - Rollup构建TS项目 安装依赖 1.全局安装rollup npm install rollup -g 2.安装TypeScript npm install typescript -Ds 3.安装TypeScript转换器npm install rollup-plugin-typescript2 -D 4安装代a码压缩插件npm install rollup-plugin-.terser -D 5安装rollup web服务 npm install rollup-plugin-seve -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
import path from "path" import ts from "rollup-plugin-typescript2" import livereload from "rollup-plugin-livereload" import serve from "rollup-plugin-serve" import replace from "rollup-plugin-replace" export default { input : './src/index.ts' , output :{ file : path.resolve (__dirname,'../lib/index.js' ), format :'cjs' , sourcemap :true }, plugins :[ ts (), livereload (), serve ({ open :true , openPage :'/public/index.html' , port :1988 }), replace ({ 'process.env.NODE_ENV' :JSON .stringify (process.env .NODE_ENV ) }) ] }
import path from "path" import ts from "rollup-plugin-typescript2" import { terser } from "rollup-plugin-terser" import replace from "rollup-plugin-replace" const isDev = ( ) => process.env .NODE_ENV === 'development' export default { input : 'src/index.ts' , output :{ file : path.resolve (__dirname,'../lib/index.js' ), format :'cjs' , sourcemap :true }, plugins :[ ts (), terser ({ compress :{ drop_console :!isDev () } }), replace ({ 'process.env.NODE_ENV' :JSON .stringify (process.env .NODE_ENV ) }) ] }
{ "name" : "rollup_ts" , "version" : "1.0.0" , "description" : "" , "main" : "index.js" , "scripts" : { "test" : "echo \"Error: no test specified\" && exit 1" , "dev" : "cross-env NODE_ENV=development rollup -c ./config/rollup.config.dev.js -w" , "build" : "cross-env NODE_ENV=production rollup -c config/rollup.config.prod.js" }, "keywords" : [], "author" : "" , "license" : "ISC" , "devDependencies" : { "cross-env" : "^7.0.3" , "rollup-plugin-livereload" : "^2.0.5" , "rollup-plugin-node-resolve" : "^5.2.0" , "rollup-plugin-replace" : "^2.2.0" , "rollup-plugin-serve" : "^1.1.0" , "rollup-plugin-terser" : "^7.0.2" , "rollup-plugin-typescript2" : "^0.31.1" , "typescript" : "^4.5.5" } }
02 - webpack构建TS项目(简单搭建构架) const path = require ('path' );const HtmlWebpackPlugin = require ('html-webpack-plugin' );const config = { entry : './src/index.ts' , mode :'development' , output :{ path :path.resolve (__dirname, 'dist' ), filename :'bundle.js' }, resolve :{ extensions : ['.ts' , '.js' ] }, module :{ rules :[ { test : /\.ts/ , use : 'ts-loader' , exclude : /node_modules/ } ] }, plugins :[ new HtmlWebpackPlugin ({ template : './public/index.html' }) ] }; module .exports = config;
{ "name" : "webpack_ts" , "version" : "1.0.0" , "description" : "" , "main" : "index.js" , "scripts" : { "test" : "echo \"Error: no test specified\" && exit 1" , "dev" :"webpack-dev-server" , "build" :"webpack" }, "keywords" : [], "author" : "" , "license" : "ISC" , "devDependencies" : { "html-webpack-plugin" : "^5.6.0" , "ts-loader" : "^9.5.1" , "typescript" : "^5.3.3" , "webpack" : "^5.89.0" , "webpack-cli" : "^5.1.4" , "webpack-dev-server" : "^4.15.1" } }
03 - esbuild+swc构建TS项目 介绍:
esbuild 是go语言编写的并且是多线程执行,性能是js的好几十倍,所以很快。
无需缓存即可实现基本打包
支持ES6跟CommonJS模块
支持ES6 Tree Shaking
体积小
插件化
其他
内置支持编译JSX
swc 则宣称其比Babel快20倍(四核情况下可以快70倍)
swc 是用rust写的,所实现的功能跟babel一样,es6语法转es5,但是速度比babel更快,前端基建工具使用rust的是越来越多了,未来可能还会有一个替代postCss的。
import esbuild from 'esbuild' ; import swc from '@swc/core' ; import fs from "node:fs" await esbuild.build ({ entryPoints : ['src/index.ts' ], loader :{ '.ts' : 'ts' , '.js' : 'js' , '.jsx' : 'jsx' , '.tsx' : 'tsx' }, treeShaking :true , define :{ 'process.env.NODE_ENV' : '"production"' , }, plugins :[ { name :"swc-loader" , setup (build ){ build.onLoad ({filter :/src\/.(js | ts | tsx | jsx)$/ },(args )=> { const content = fs.readFileSync (args.path ,'utf-8' ) const {code} = swc.transformSync (content,{ filename :args.path }) return { contents :code } }) } } ], outdir :'dist' })
注意:在package.json中加上type:”module”
启动指令:ts-node-esm config.ts
04 - TS编写发布订阅模式
具体代码:on订阅/监听 emit发布/注册 once只执行一次 off解除绑定
interface List { [key : string ]: Function ; } interface EventFn { on (name : string , fn : Function ): void ; emit (name : string , ...agrs : any []): void ; off (name : string ): void ; once (name : string , fn : Function ): void ; } class Dispatch implements EventFn { private list : List ; constructor ( ) { this .list = {}; } on (name: string , fn: Function ) { this .list [name] = fn; } emit (name: string , ...agrs: any [] ) { if (this .list [name]) { this .list [name].apply (this , agrs); } else { console .error (`名称错误${name} ` ); } } off (name: string ) { if (this .list [name]) { delete this .list [name]; } else { console .error (`名称错误${name} ` ); } } once (name: string ,...agrs: any [] ) { if (this .list [name]) { this .emit (name,...agrs); this .off (name); } else { console .error (`名称错误${name} ` ); } } } export default new Dispatch ();
05 - set、map、weakset、weakmap使用
set和map
const set :Set <number > = new Set ([1 , 2 , 3 , 4 , 4 ]); set.add (5 ) set.delete (1 ) set.clear () set.has (1 ) set.forEach set.entries () set.keys () const obj = {name :"pan" }const map :Map <Object ,any > = new Map () map.set (obj,"asnfa" ) map.delete (obj) map.has (obj) map.clear () map.entries () map.keys ()
weakset 和weakmap
注意:weakset 和weakmap为弱引用不会被计入垃圾回收机制的
let obj :any = {name :'pansida' } const weakmap :WeakMap <Object ,any > = new WeakMap ()weakmap.set (obj, '123' ) obj = null console .log (weakmap.get (obj)) let arr :any = [1 ,2 ,3 ,4 ] const weakset :WeakSet <any > = new WeakSet ()weakset.add (arr) arr = null console .log (weakset.has (arr))
06 - proxy和Reflect proxy就是数据劫持
const obj = { name : "xiaopan" };const objProxy = new Proxy (obj, { get (target, key, receiver ) { return Reflect .get (target, key, receiver); }, set (target, key, value, receiver ) { return Reflect .set (target, key, value, receiver); }, deleteProperty (target, key ) { return Reflect .deleteProperty (target, key); }, has (target, key ){ console .log ("我触发了" ); return Reflect .has (target, key); }, ownKeys (target ){ return Reflect .ownKeys (target); }, apply (target, thisArg, argArray ){ }, construct (target,thisArg,argArray ){ return {} } }); if ('xiaopan' in objProxy){ console .log (111 ); }
const list :Set <Function > = new Set ()const autorun = (cb:Function )=>{ if (!list.has (cb)){ list.add (cb) } } let observable = <T extends object >(param:T )=> { return new Proxy (param,{ get (target,value ){ return Reflect .get (target,value) }, set (target,value,newValue ){ list.forEach (fn =>fn ()) return Reflect .set (target,value,newValue) } }) } autorun (()=> { console .log ('我被改变了' ); }) const obj = observable ({name :'张三' ,age :20 })obj.name = '李四'
07 - 类型守卫(面试题) const isObject = (data:any )=> ({}).toString .call (data) === '[object Object]' ;const isnumber = (data :any ):data is number => typeof data === 'number' ;const isstring = (data :any ):data is string => typeof data === 'string' ;const isfunction = (data :any ):data is Function => typeof data === 'function' ;function handleTest (data:any ){ if (isObject (data)){ Object .keys (data).forEach (index => { let val = data[index] if (isnumber (val)){ data[index] = val.toFixed (2 ) } if (isstring (val)){ data[index] = val.trim () } if (isfunction (val)){ data[index]() } }) } } const obj = { a :10.3412 , b :' hello world ' , c :function ( ){ console .log (this ); console .log ('hello function' ) } } handleTest (obj)
08 - 协变、逆变、双向协变 (类型兼容性) 所谓的类型兼容性,就是用于确定一个类型是否能赋值给其他的类型。ypeScript中的类型兼容性是基于结构类型的(也就是形状),如果A要兼容B那么A至少具有B相同的属性。
interface A { name :string , age :number } interface B { name :string , age :number , gender :string } let a :A = {name :'a' , age :18 }let b :B = {name :'b' , age :18 , gender :'male' }a = b let fnA = (p:A )=>{};let fnB = (p:B )=>{};fnB = fnA; fnB = fnA fnA = fnB
09 - 泛型工具
Partial属性可选的意思
Required属性必选的意思
Pick提取部分属性
Exclude排除部分属性
Omit排除部分属性并且返回新的类型
Record 约束对象key以及value
ReturnType 获取函数类型的返回值
Partial
interface A { name : string ; age : number ; gender : string ; } type PartialA = Partial <A>;type PartialATest <T> = { [P in keyof T]?: T[P] }
Required
interface A { name?: string ; age?: number ; gender?: string ; } type PartialA = Required <A>;type PartialATest <T> = { [P in keyof T]-?: T[P] }
Pick
interface A { name?: string ; age?: number ; gender?: string ; } type PickA = Pick <A, 'name' | 'age' >;type PickATest <T,K extends keyof T> = { [Key in K]:T[Key ] }
Exclude
type ExcludeA = Exclude <'name' | 'gender' | 'age' ,'age' >;type ExcludeATest <T,K> = T extends K ? never : T
Omit
interface A { name?: string ; age?: number ; gender?: string ; } type OmitA = Omit <A, 'a' >;type OmitATest <T,K> = Pick <T,Exclude <keyof T,K>>
Record
type Key = 'name' | 'age' | 'gender' type Value = 'x' | 'y' | 'z' type Test = Record <Key , Value >type Test1 = keyof any type RecordTest <T extends Test1 ,K> = { [P in T]: K } const test : RecordTest <Key ,Value > = { name : 'x' , age : 'y' , gender : 'z' }
ReturnType
let fn = ( )=> [1 ,2 ,3 ]type ReturnTest = ReturnType <typeof fn> type ReturnTypeTest <T> = T extends (...agrs :any [])=>infer R? R :never type ReturnTest2 = ReturnTypeTest <typeof fn>
10 - infer 关键字 interface User { name : string ; age : number ; } type PromiseType = Promise <User >type GetPromiseType <T> = T extends Promise <infer X> ? X : T;type T = GetPromiseType <PromiseType >type PromiseType1 = Promise <Promise <User >>type GetPromiseType1 <T> = T extends Promise <infer X> ? GetPromiseType1 <X> : T;type T1 = GetPromiseType1 <PromiseType1 >type inferTest1<T> = T extends { name : infer U,age :infer U } ? U : never ;type T2 = inferTest1<User > type inferTest2<T> = T extends {a :(name:infer U )=> void ,b :(age:infer U )=> void }? U :Ttype T3 = inferTest2<{a :(name:string )=> void ,b :(age:number )=> void }>
11 - infer 提取元素妙用 type Arr = ['a' ,'b' ,'c' ]type First <T extends any []> = T extends [infer First ,...agrs :any []]? First :never type FirstTest = First <Arr >type Last <T extends any []> = T extends [...agrs :any [],infer Last ]? Last :never type LastTest = Last <Arr >type Pop <T extends any []> = T extends [...infer First ,unknown ] ? First :never type PopTest = Pop <Arr >type Shift <T extends any []> = T extends [unknown ,...infer Last ] ? Last :never type ShiftTest = Shift <Arr >
12 - TS用法递归 type Arr = [1 ,2 ,3 ,4 ]type ReverseArr <T extends any []> = T extends [infer First ,...infer Rest ]?[...ReverseArr <Rest >,First ]:Ttype newArr = ReverseArr <Arr >
13 - 插件编写(localstroageTime 编写 有时间的localstroage)
export enum Dictionaries { permanent = 'permanent' , expire = '__expire__' }
import { Dictionaries } from "../enum/index" export type Key = string ;export type TimeLimit = number | Dictionaries .permanent ;export type Data <T> = { value : T; [Dictionaries .expire ]: Dictionaries .permanent | number ; }; export interface Result <T> { message : string ; value : T | null ; } export interface LocalStorageTimeCls { get<T>(key : Key ): Result <T | null >; set<T>(key : Key , value : T, TimeLimit : TimeLimit ): void ; remove (key :Key ): void ; clear (): void ; }
import {Data , Key , LocalStorageTimeCls ,Result ,TimeLimit } from "./types/index" import {Dictionaries } from "./enum/index" class LocalStorageTime implements LocalStorageTimeCls { get<T>(key :Key ):Result <T | null >{ const value = localStorage .getItem (key) if (value){ const obj :Data <T> = JSON .parse (value) const date = new Date ().getTime () if (typeof obj.__expire__ === "number" && obj.__expire__ < date){ this .remove (key) return { message :"缓存已过期" , value :null } }else { return { message :"获取成功" , value :obj.value } } }else { return { message :`你的${key} 值无效!` , value :null } } } set (key:Key,value:any ,TimeLimit:TimeLimit = Dictionaries.permanent ){ const data = { key, value, [Dictionaries .expire ]:TimeLimit } localStorage .setItem (key,JSON .stringify (data)); } remove (key:Key ){ localStorage .removeItem (key) } clear ( ){ localStorage .clear () } } export default new LocalStorageTime ()