搜索
简帛阁>技术文章>ts必备基础知识总结

ts必备基础知识总结

语法篇

一、基本类型

数据类型关键字/描述用法
数字类型numberlet decLiteral: number = 6
布尔类型booleanlet flag: boolean = true;
字符串类型stringlet name: string = “Runoob”
数组类型array// 在元素类型后面加上[]
let arr: number[] = [1, 2];
// 使用数组泛型
let arr: Array = [1, 2];
元组固定元素数量和类型,类型可不一致,
但位置必须一样
let x: [string, number];
x = [‘Runoob’, 1]; // 运行正常
x = [1, ‘Runoob’]; // 报错
console.log(x[0]); // 输出 Runoob
枚举enum/定义数值集合enum Color {Red, Green, Blue};
let c: Color = Color.Blue;
console.log©; // 输出 2
voidvoid/表示该方法没有返回值function hello(): void {
//没有return 返回值
}
nullnull/对象值缺失let n: null = null;
undefinedundefined/未定义的值let u: undefined = undefined;
nevernever/never 是其它类型(包括 null 和
undefined)的子类型,代表从不会出现的值
// 返回never的函数必须存在无法达到的终点
function error(message: string): never { throw new Error(message); }
unknownunknown/unknown类型只能赋值给any类型和unknown类型let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error

补充

enum类型

映射对应数据

1. 数字枚举:初始值可自动增长
实际场景:文章分类有固定的id 这时候就可以使用到枚举去定义

enum Category {<!-- -->
  Work,//这里是有默认初始值 为 0 依次增长 
  Life,
  Study,
}
  let cateGoryId: Category =Category.Study
  console.log(cateGoryId)// 2

2.字符串枚举
定义的成员必须都是字符串
比如每个人会取自己的英文名,对应的英文名和真实人名,可以去做一一映射

enum Person {<!-- -->
  jack = '小王',
  role = '小蓝',
  Anna = '小红',
}
  let person: Person =Person.Anna
  console.log(person)//小红

3.异构枚举
异:就是里面成员既有数字又有字符串,大杂炖

enum mess {<!-- -->
  jack = '小王',
  role = '小蓝',
  Anna = '小红',
     c = 1,
     b = 2
}

二、断言

类型断言必须联合类型中的一种,类型断言只是做类型选择,而不是做类型转换
编译阶段起作用
在定义一个变量为联合类型时,要去做判断会遇到以下的情况

const unionGetLength2 = (something: string | number): number => {<!-- -->
    if(something.length){<!-- --> //报错something无法去判断到底时哪个类型
        return something.length;
    } else {<!-- -->
        return something.toString().length;
    }
}

可以用断言去处理上面这个类型不能判断的问题,断言有两种写法:

  1. as语法
  2. 尖括号语法

1. as语法(值 as 类型)

const assertionGetLength = (something: string | number): number => {<!-- -->
    if((something as string).length){<!-- -->//告诉TS something 就是字符串类型
        return (something as string).length;
    } else {<!-- -->
        return something.toString().length;
    }
}

2. 尖括号语法(<类型>值)

const assertionGetLengthOther = (something: string | number): number => {<!-- -->
    if((<string>something).length){<!-- --> 告诉ts something就是字符串类型
        return (<string>something).length;
    } else {<!-- -->
        return something.toString().length;
    }
}

三、类型守卫

1. 类型守卫

1.1 什么是类型守卫

当遇到条件语句时,会 ** 限制变量类型

  • 类型判断: typeof
  • 实例判断: instanceof
  • 属性判断: in
  • 字面量相等判断:==,===,!=, !==

1.2 类型判断(typeof)

function test(own: string | boolean | number) {<!-- -->
  if (typeof own == 'string') {<!-- -->
    // 这里 own 的类型限制为 string
  } else if (typeof own == 'number') {<!-- -->
    // 这里 own 的类型限制为 number
  } else {<!-- -->
      // 这里 own 的类型限制为 boolean
  }
}

1.3 属性判断(in)

interface one {<!-- -->
  name: string;
  speak:string;
}

interface two {<!-- -->
  age: number;
  see:string;
}


function test(own:one | two){<!-- -->
  console.log("Name: " + own.name);
  if ("name" in own) {<!-- --> 
    //这里限制为own 对象为one
    console.log(own.speak);
  }
  if ("see" in own) {<!-- -->
    //这里限制为own限制的对象为two
    console.log(own.see);
  }
}

1.4 实例判断(instanceof)

interface  Padder {<!-- -->
  getPaddingString():string
}
class Space implements Padder {<!-- -->
  constructor(private numSpaces: number) {<!-- -->} 
  getPaddingString() {<!-- -->
    return Array(this.numSpaces + 1).join(' ');
  }
}
class StringPadder implements Padder {<!-- -->
  constructor(private value: string) {<!-- -->}
  getPaddingString() {<!-- -->
    return this.value;
  }
}

function getrandom() {<!-- -->
  return Math.random() < 0.5 ? new Space(4) : new StringPadder('');
}

let padder: Padder = getrandom();

//判断padder是否是Space的实例对象,如果中间有其他值覆盖了,会出现问题
if (padder instanceof Space) {<!-- -->
  //判断后,确保这个值是它的实例对象 padder类型收缩在'SpaceRepeatingPadder'
}

2. 自定义类型守卫

返回布尔值条件函数

function isString (own: any): own is string {<!-- -->
  return typeof own === 'string';
}
function test (xdom:any) {<!-- -->
 if (isString(xdom)) {<!-- -->
    	//xdom 限制为 'string'
    } else {<!-- -->
     //其他类型
    }
}

四、联合类型和类型别名

1. 联合类型

取值可以为多种类型中的一种
特点:1.使用的属性和方法需要类型共有的
2.通常与 null 或 undefined 一起使用:

let stringAndNumber: string | number;

2. 类型别名

类型另一个外号,用type定义

不用类型别名:
let greet = (message: string | string[]) => {<!-- -->
  // ...
};
用类型别名:
type Message = string | string[];
let greet = (message: Message) => {<!-- -->
  // ...
};

五、交叉类型

同时满足多个类型,多种类型叠加成为一种类型,要包含所需所有类型的特性

interface IPerson {<!-- -->
  id: string;
  age: number;
}

interface IWorker {<!-- -->
  companyId: string;
}

type IStaff = IPerson & IWorker;//定义IStaff类型 同时满足这两个接口类型条件

const staff: IStaff = {<!-- --> //staff我i IStaff类型 必须一起满足才可
  id: 'E1006',
  age: 33,
  companyId: 'EFT'
};

console.dir(staff)

六、函数

TypeScriptJavaScript
含类型无类型
箭头函数箭头函数(ES2015)
函数类型无函数类型
必填和可选参数所有参数都是可选的
默认参数默认参数
剩余参数剩余参数
函数重载函数重载

1. 普通函数

可以定义函数的参数类型和返回值

function createUserId(name:string,id:number) {<!-- -->
	return name + id
}

2. 箭头函数

let createUserId:(name:string,id:number)=>string

3. 可选参数

?表示这个参数是可选的
注意:可选参数要放在普通参数后面,不然会导致编译错误

function createUserId(name:string,id:number,age?:number) {<!-- -->
	return name + id;
}

4. 默认参数

默认name这个参数的值为Jons

function createUserId(name:string = 'Jons',id:number) {<!-- -->
 return name + id;
}

5. 剩余参数

简写,可以把剩余后面写的那些参数一起表示

function push(array,...items) {<!-- -->
  console.log(items)
}
push(a,1,2,3) //items是个数组 [1,2,3]

6. 函数重载

常见的根据参数的类型执行不同的函数
多数用于传入不同的参数得到不同的结果
重载分两个部分:1.声明 2.实现 缺一不可

6.1 重载使用场景

例1:
例如我们有一个add函数,可以接收string 类型相拼接,也可以接收number类型,相加

//声明:
function add (arg1: string, arg2: string): string
function add (arg1: number, arg2: number): number 
//实现,
function add (arg1: string | number, arg2: string | number) {<!-- -->
  // 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 arg1 + arg2
  if (typeof arg1 === 'string' && typeof arg2 === 'string') {<!-- -->
    return arg1 + arg2
  } else if (typeof arg1 === 'number' && typeof arg2 === 'number') {<!-- -->
    return arg1 + arg2
  }
}

注意:如果实现部分没有严格判断,会提示此重载签名与其实现签名不兼容。函数重载只是多个函数声明,逻辑依旧要自己写,并不会把我们声明的多个函数进行合并

例子2 :
写个函数test,当传入参数 param 是User时,不传入flag,当传入的param时number时,传入flag
下面看看不用重载:

interface User {<!-- -->
  name: string;
  age: number;
}

declare function test(param: User | number, flag?: boolean): number;
const user={<!-- -->
name:'Jack',
age:18
}
const res=test(user,false) //虽然不报错,但是与想法违背 当传入的是User是 此时应该不让传入flag

重载解决上诉问题:

interface User{<!-- -->
	name:string;
	age:number;
}
declare function  test(params:User):number;
declare function  test(params:number,flag:boolean):number;
const user={<!-- -->
  name:'jack',
  age:666
};
//类型“{ name: string; age: number; }”的参数不能赋给类型“number”的参数。ts(2345)
const res=test(user,false);

实际项目中的用法:
有声明之后,需要有具体的实现

interface User{<!-- -->
  name:string;
  age: number;
}
const user:User ={<!-- -->
  name:'jack',
  age:  123
}
class oneClass {<!-- -->
  //声明
  public test(param: User): number;
  public test(param: number, flag: boolean): number;
  //实现
  public test(param: User | number, flag?:boolean) {<!-- -->
    if (typeof param==='number') {<!-- -->
      return param+(flag?1:0)
    }else{<!-- -->
      return param.age
    }
  }
}

如果传入的参数不同,但是得到的结果是一样的,那么重载就意义不大了
重载个人觉得比较繁琐,一些可以用其他方法代替重载,反而更加的简单
例如:
可选参数来代替

function func (a: number): number
function func (a: number, b: number): number
//代替上面:
function func (a: number, b?: number): number

联合类型来代替:

function func (a: number): number
function func (a: string): number
//替代上面
function func (a: number | string): number

七、数组

ts在这个过程是类型校验,如果定义该类型,与后面数组对应数据冲突,会提示

//不能将类型 “ number ” 分配给类型 “ string ”
let x: number;
let y: number;
let z: string;
let five_array = [0, 1, 2, 3, 4];
[x, y, z] = five_array;

1. 基本类型的数组

定义一个只包含数字的数组:

const arr: number[] = [1,2,3]

既存数字又存字符串:

const arr1: (number | string)[] = [1, '2' ,3]

2. 对象类型数组

const objectArr: {<!-- -->name: string, age: number}[] = [{<!-- -->name:'a', age:16}]

3. 与元组对比

元组本质上也是数组,所以数组上的操作元组也可以去使用 一个数组里面的长度和类型都是固定的时候,就可以使用元祖

const teacherinfo2: [string, string, number] = ['zina', 'girl', 18];
//这里是固定长度以及固定了每一个的类型,如果类型不一样会提示

八、接口

接口来定义对象的类型

1. 写法

1.首字母大写
2.变量的形状必须和接口的形状保持一致
举个栗子:

interface Person {<!-- -->
  name:string
  age:number
}
let jack:Person = {<!-- --> //变量的类型必须和上面是保持一致的
	name:'jack',
     age:18
}

2. 可选属性

和数组一样,对象里面的属性是可选的,我们经常需要不一样形状的对象

interface Person {<!-- -->
  name:string
  age?:number
}
  let jack:Person = {<!-- --> 
	name:'jack' // age 可以不写
}

3. 任意属性

用于不确定属性的数量的场景
确定属性和可选属性都必须符合任意属性的类型
如果不符合如下:

interface Person {<!-- -->
  name: string;
  age?: number;
  [propName: string]: string;
}
//类型“number”的属性“age”不能赋给字符串索引类型“string”。

正确写法:

interface Person {<!-- -->
name:string;
age?:number;
[proppName:string]:any;
}

4. 只读属性

有些字段只能在创建的时候被赋值,其他时候不允许被更改,可以使用只读属性

interface Person {<!-- -->
    readonly id: number;
    name: string;
    age?: number;
    [propName: string]: any;
}

let tom: Person = {<!-- -->
    name: 'Tom',
    gender: 'male'
};

tom.id = 89757;
//无法分配到 "id" ,因为它是只读属性

九、泛型

类型不明确,但是要求其中一部分或者全部类型是一致的情况

使用场景

在不知道变量类型的情况下定义: 如果要求first输入的类型,second必须一样 这时候下面这个代码就不能做到了
可以用泛型解决这个的问题

function test(first:any,second:any){<!-- -->
  return `${<!-- -->first}+${<!-- -->second}`
}

泛型解决:T为自定义的,取ABC都可以

function test<T>(first:<T>,second:<T>){<!-- -->
  return `${<!-- -->first}+${<!-- -->second}`
}
test<number>(1,1)
test<number>(1,'1')//报错

可以定义一个数组里面的类型

function map<T>(params:T[]){<!-- -->
  return params
}
另一个写法
function map<T>(params:Array<T>){<!-- -->
  return params
}

map<string>([1,'1'])//报错
map<string>(['1','1'])

定义多个泛型:

function test<T,P>(first:T,second:P):T{<!-- -->
 return first  //要求返回值和first 的类型一致
}
test<string,number>('1',1)
test('1',1) //不定义类型也可以,ts会自动推断出该T是string类型和P是number类型

十、类

1. 如何定义一个类

class Person {<!-- -->
  name = 'dell'
  getName(){<!-- -->
    return this.name;
  }
}
const person = new Person();
console.log(person.getName())//dell 

2. 类的继承

class Person {<!-- -->
  name = 'dell'
  getName(){<!-- -->
    return this.name;
  }
}
class Teacher extends Person {<!-- -->
  getTeacherName(){<!-- -->
    return 'teacher'
  }
}
const teacher = new Teacher(); //声明的teacher实例里面 既有getName方法 又有getTeacherName
console.log(teacher.getName()); //dell
console.log(teacher.getTeacherName()) //teacher

3. 类的重写和super

在继承了父类方法之后,可以子类方法里面去重写父类的方法
注意:覆盖了之后,还需调用父类的方法,可以用 super 去调用

class Person {<!-- -->
  name = 'dell'
  getName(){<!-- -->
    return this.name;
  }
}
class Teacher extends Person {<!-- -->
  getTeacherName() {<!-- -->
    return 'teacher';
  }
  getName() {<!-- -->
    return 'lee';
  }
}
console.log(teacher.getName());//lee 这个时候子类的getName把父类的getName给覆盖了
// 如果Teacher 写成如下
class Teacher extends Person {<!-- -->
  getTeacherName() {<!-- -->
    return 'teacher';
  }
  getName() {<!-- -->
   // super.getName()//调用的是父类的方法
    return 'lee' + super.getName();
  }
}

4. 访问类型

4.1 private 私有的

允许在类内被使用
首先明确什么是类内,什么是类外

class Person {<!-- -->
 private name = 'dell'
  getName(){<!-- -->
   console.log(this.name)//类内 可以被调用
  }
}
const person = new Person()
console.log(person.name) //这个是类外 报错

4.2 protected 被保护的

允许在类内及继承的子类中使用

class Person {<!-- -->
 protected name = 'dell'
  getName(){<!-- -->
   console.log(this.name)//类内 可以被调用
  }
}
class Teacher extends Person {<!-- -->
  getTeacherName() {<!-- -->
   console.log(this.name)//继承了父类的name 允许被调用
  }
}

4.3 public 公共的

允许我在类内外被调用,不写的情况默认就是public

class Person {<!-- -->
  name = 'dell'//默认前面都是public name
  getName(){<!-- --> //默认前面都是public getName
   console.log(this.name)
  }
}
const person = new Person()
console.log(person.name)

5. constructor 构造函数

new 实例的时候 这个瞬间 constructor()被会马上执行

传统写法:
class Person {<!-- -->
  public name:string
  constructor(name:string){<!-- -->
    this.name=name
 }
}
const person =new  Person('dell')
console.log(person.name)
可以简化为:
class Person {<!-- -->
  constructor(public name: string) {<!-- -->
  }
}

继承中父子构造器冲突的情况:
继承之后 如果父类有构造器 子类也有构造器的时候 子类必须调用父类的构造函数。还必须按照父类的构造器的要求把参数传入

class Person{<!-- -->
constructor(public name:string){<!-- -->

}
}
class Teacher extends Person{<!-- -->
  constructor(public age:number){<!-- -->
    super('dell')
  }
}
const teacher =new Teacher(28)
console.log(teacher.age)//28
console.log(teacher.name)//dell

6. getter和setter

举个栗子:
假设某类有一个私有变量,但是又需要向外界去暴露这个私有变量,然后不能被外界知道这个变量的具体情况
可以用下面方法实现:
这里的getter和setter 可以对变量进行处理加工之后,向外界暴露,外界直接调用get/set的方法去读取更改_name这个属性

class Person{<!-- -->
  constructor(private _name:string){<!-- -->
  get name(){<!-- -->
    return this._name+' lee'; //可以将name加密之后暴露出去
  }
  set name(name:string){<!-- --> //也可以保护变量
    const realName=name.split('')[0]; //对得到的name 进行一个处理
    this._name=realName
  }
}
const person=new Person('dell')
console.log(person.name);//dell lee 不需要括号 
person.name ='dell lee'

7. 例子(单例模式)

永远只生成一个实例,当发现 instance 已经创建了之后,就不再创建实例了

class Demo{<!-- -->
  private static instance:Demo 
  private constructor(public name:string){<!-- -->}// 不允许被调用 规避创建实例的情况
  static getInstance(){<!-- -->
    if(!this.instance){<!-- --> //如果没有创建  创建让instance储存
    this.instance = new Demo('dell lee')
  }
    return this.instance;
  }
  
}
const demo1 =Demo.getInstance();

8. 抽象类

主要是把有共性的部分去做一个封装
抽象类只能被继承 不能被 new

抽象类的用法 extends 子类如果继承了父类的抽象类之后,必须在子类里面去实现父类的抽象方法
举个栗子:算长方形,圆形 椭圆的面积 直接写 class 那么每个 class 下面都需要写这个方法,这个方法可以被提取出来写在抽象类里,再长方形,圆形,椭圆都去继承这个抽象类,各个形状的面积计算公式是不一样的,具体实现在自己的类里面去写

具体写法:

abstract class Geom{<!-- --> //abstract 去定义一个抽象类
  getType(){<!-- -->
    return 'gemo';
  }
  abstract getArea():number //抽象方法 没有具体实现
}
class Circle extends Geom{<!-- -->
  private r:number
getArea(){<!-- -->
  return '123'
}

}
class Square extends Geom{<!-- -->
getArea(){<!-- -->
  return 'hello'
}
}
class Triangle extends Geom{<!-- -->
getArea(){<!-- -->
  return ''
}
}

十一、装饰器

1. 什么是装饰器

修饰的工具
装饰器本身是一个函数

2. 装饰器种类

  • 类的装饰器
  • 方法的装饰器
  • 访问器的装饰器
  • 属性的装饰器
  • 参数的装饰器

3. 类的装饰器

3.1 如何写一个装饰器

通过@符号来使用,不能直接使用装饰器,在标准里面属于实验性质的语法,需要在 tsconfig.json 文件中把配置项打开


function testDecorator(constructor:any){<!-- -->
  constructor.prototype.getName = () =>{<!-- -->
    console.log('dell')
  }
  console.log('decorator')
}
@testDecorator
class Test{<!-- -->}//运行时机 会在类创建好之后,立马执行


const test = new Test();

3.2 多个装饰器的执行顺序

收集的时候是从上到下依次收集
但是执行的时候会从下到上

function testDecorator1(constructor:any){<!-- -->
  console.log('decorator1')
}
function testDecorator2(constructor:any){<!-- -->
  console.log('decorator2')
}
@testDecorator1
@testDecorator2
class Test{<!-- -->}
//控制台:
//decorator2
//decorator1

3.3 装饰器包装

有时候装饰器里面会存在一些判断,可以用工厂模式去包装装饰器,里面返回一个函数

function testDecorator(flag:boolean){<!-- --> //接收装饰器的参数
  if (flag) {<!-- -->
    return function (constructor: any) {<!-- -->
      constructor.prototype.getName = () => {<!-- -->
        console.log('dell');
      };
      console.log('decorator');
    };
  }else{<!-- -->
    return function (constructor: any) {<!-- -->}
  }
 
  
}
@testDecorator(false)//装饰器返回的是一个函数,然后再调用该函数
class Test{<!-- -->}

4. 方法装饰器

方法装饰器接收三个参数

  • targe:普通方法, target 对象的是类的 prototype ,如果是静态方法 target对应的是类的构造函数
  • key:普通方法 key 装饰的方法的名字
  • descriptor: 属性描述符
function getNameDecorator(target:any,key:string,descriptor:PropertyDecorator){<!-- -->
  console.log(target, key, descriptor);
};

在创建完实例之后,对方法进行修改,如何让方法不被修改呢?如何让方法的原始值进行修改?
可以用 descriptor去控制

function getNameDecorator(target:any,key:string,descriptor:PropertyDescriptor){<!-- -->
  console.log(target, key, descriptor);
  descriptor.writable=false //方法不允许被修改
  descriptor.value = function() {<!-- --> //让方法里面返回的原始值进行修改
    return 'yeyeyeye'
  }
};
class Test{<!-- -->
  name:string;
  constructor(name:string){<!-- -->
    this.name=name;
  }
  @getNameDecorator
  getName(){<!-- --> //class创建好之后,立刻对方法做一个装饰
    return this.name
  }
}
const test =new Test ('dell')
test.getName=()=>{<!-- --> //error
  return '123'
}

5. 访问器的装饰器

访问器的装饰器接收的参数和方法装饰器是一样的
访问器装饰器接收三个参数

  • targe:普通方法,target 对象的是类的prototype,如果是静态方法 target对应的是类的构造函数
  • key:普通方法 key 装饰的方法的名字
  • descriptor: 属性描述符

给set去写一个装饰器:

function visitDecorator(
  target: any,
  key: string,
  descriptor: PropertyDescriptor
) {<!-- -->
  console.log(target, key, descriptor);
  descriptor.writable = false; //方法不允许被修改
};
class Test{<!-- -->
private  _name:string;
  constructor(name:string){<!-- -->
    this._name=name;
  }
  get name() {<!-- -->
    return this._name;
  }
  @visitDecorator
  set name(name:string){<!-- -->
    this._name = name;
  }
}
const test =new Test ('dell')
test.name = '123123' //走的是 set 方法 会报错 set 上面的装饰器写了descriptor.writable = false 方法不允许被修改
console.log(test.name) //走的是 get 方法

6. 属性的装饰器

属性装饰器接收两个参数

  • targe:普通方法, target 对象的是类的 prototype,如果是静态方法 target 对应的是类的构造函数
  • key:被修饰的属性名

可以自己定义descriptor 返回 新的descriptor 可以去覆盖原始 name 的descriptor
比如下面:name 是可以进行修改的,自己定义descriptor 将 writable 更改成 false 之后 将不能被修改了

function nameDecorator(
  target: any,
  key: string,
):any{<!-- -->
  console.log(target, key);
  const descriptor :PropertyDescriptor ={<!-- -->
    writable:false
  }
  return descriptor;
};
class Test{<!-- -->
 name:string='dell';
}
const test =new Test ()
test.name = '123123'

7. 参数的装饰器

参数装饰器接收三个参数

  • targe:原型
  • method:方法名
  • paramIndex:参数所在的位置
function paramDecorator(target: any, method: string,paramIndex:number): any {
  console.log(target, method, paramIndex); //原型 getinfo 0
};
class Test{
 getinfo(@paramDecorator name:string,age:number){
   console.log(name,age)
 }
}
const test =new Test ()
test.getinfo('dell',30)

Vue.js+TS项目实践

1.项目环境搭建

npm i -g @vue/cli //安装 vue 脚手架
vue create vueAddts //创建 vue 项目
vue add @vue/typescript //创建 @vue/typescript
npm i vuex  //安装 vuex

2.Vuejs版与Vuejs+TS版区别

TS版: 需要先去导入两个组件 Component , Vue
Component组件注解,用来注册组件
vue-property-decorator 属性装饰器
如下:

<script lang="ts">
import {<!-- --> Component, Vue } from 'vue-property-decorator'
import ResList from '@/components/ResList.vue'

@Component({<!-- -->
  components: {<!-- -->
    ResList
  }
})
export default class extends Vue {<!-- -->}

Vue版:对象的方式去描述整个vue

<script>
export default {<!-- -->
  name: "App",
  data(){<!-- -->
  return{<!-- -->}
  }
};
</script>

3.项目地址

项目跟着TS+Vue.js视频写的一个标签应用,对新手非常友好,强烈推荐小伙伴去看~
功能:对标签添加删除分类修改
感兴趣的可以点击这项目链接查看

4.了不起的 tsconfig.json 指南

写项目的时候没有太关注这边,所以贴大佬链接,想看的小伙伴转场啦~ 了不起的 tsconfig.json 指南

语法篇一、基本类型数据类型关键字/描述用法数字类型numberletdecLiteral:number6布尔类型booleanletflag:booleantrue;字符串类型stringletnam
TS】学习总结01TypeScript编译环境TypeScript全局安装npminstalltypescriptgtscversion//查看版本,安装成功TypeScript运行环境常规路径ts
什么是SQL注入(SQLInjection)所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接
我们都知道,ASP是ActiveServerPage的缩写,意为“动态服务器页面”。ASP是微软公司开发的代替CGI脚本程序的一种应用,它可以与数据库和其它程序进行交互,是一种简单、方便的编程工具。下
不管是自我定位太高,还是职位层次太低,系统复习了一遍很久没有摸过的C++总是有好处的。总结如下:一、new和malloc的区别1、new和delete配对,释放数组需要用delete[]。new和de
组件基础1组件的复用组件是可复用的Vue实例。<!DOCTYPEhtml><html><head><metacharset"utf8"><styl
在软件系统组成越发复杂的今天,如何保证每个服务间的通信,是系统架构师必须考虑的重要一点。作为一名软件测试工程师,了解系统架构以及服务间的通信过程及原理,对我们开展测试工作有很大的帮助。这篇博客,简单介
计算机网络学习的核心内容就是网络协议的学习。网络协议是为计算机网络中进行数据交换而建立的规则、标准或者说是约定的集合。因为不同用户的数据终端可能采取的字符集是不同的,两者需要进行通信,必须要在一定的标
目录标签分类常用标签表单框架常用的布局组合标签HTML4和HTML5的区别:HTML5中新增的语义标签了解HTML5新的表单属性form新属性input新属性HTML5新的表单元素了解HTML5中新的
!注释方式单行/**/多行1SELECTcolumn1,column2,column3FROMtablenameWHEREid<5;2SELECTDISTINCTcolumn1,column2F