随着前端的发展,js越来越火,但是js有许多不合理或者说不完美的地方
尽管从es5,es6,es7等版本升级能为js完善了不少地方,但是js始终是一个弱类型语言,稍微不注意会出现很多奇怪的bug,于是ts变得越来越重要,越来越受重视了.
ts中的基础类型
//数字number类型
const num: number = 123;
//字符串string类型
const str: string = 'abc';
//数组array类型,2种方式
const arr1: number[] = [1, 2, 3]; //里面的元素只能是数字类型
const arr2: Array<number> = [1, 2, 3]; //和上面一样
//元祖类型tuple 属于数组的一种,可以指定里面的元素为不同类型
const arrT: [number, string] = [123, 'abc'];
//枚举enum
enum Flag {error, success} //error就是0,success就是1
// enum Flag {error = 1, success = 0}//也可以自行指定
let state: Flag = Flag.success; //1
//any类型,其实等于没指定..
let anyType:any = 123; //先是声明为数字
anyType = 'abc'; //然后再声明为abc也不会报错,因为是any
// null和undefined
let numUn:number|null|undefined ;
let a:null = null;//null类型就只能为null
let b:undefined = undefined; //undefined类型就只能为undefined
// void 一般用于定义函数没有返回值
function test():void{ //表示函数没有返回任何类型
return 2 //会报错
}
//never类型,从来不会出现的类型,多数用于总是会抛出异常,或根本不会有返回值的类型
function error(message: string): never {
throw new Error(message);
}
ts中函数的定义
//声明返回值
function test(name: string, age: number): string {
//入参必填name类型为string,必填age类型为number,返回值为string
return `name:${name},age:${age}`
}
//没有返回值
function test2(name: string, age: number): void {
//void代表没有返回值
console.log(name);
console.log(age);
}
//可选参数
function test3(name: string, age?: number): void {
//加个?可以设置为选填,但是如果要填一定要复合声明的类型
//注意点:可选参数不能设置在必填参数前面
console.log(name);
console.log(age);
}
//函数重载,在js中,两个相同名称的函数会被覆盖,ts中可以触发重载
function plus(num: number):number; //输入number,输出number
function plus(num: string):number; //输入string,输入number
function plus(num: any):any{
//上面两个算重载,这个不算,这个是写具体的操作,这个函数只能穿number和string其他会报错
switch (typeof num){
case 'number':
return num+10;
case 'string':
return parseInt(num) + 10;
default:
return NaN;
}
}
console.log(plus(10)); //20
console.log(plus('10')); //20
console.log(plus(true)); //ts会报错
ts中的类
//ts中的类
class Person{
name:string;
constructor(name:string){
this.name = name;
// console.log(this.sayName());
}
sayName():string{
return this.name
}
}
const p = new Person('joy');
p.sayName();
//ts中的类继承
class Child extends Person{
age:number;
constructor(age:number,name:string){
super(name);
this.age = age;
}
sayAge():number{
return this.age
}
}
const c = new Child(12,'ball');
c.sayAge();
c.sayName();
// public :公有都能访问
// protected :保护只能在自身类里面,子类里面可以通过this访问,类外面包括实例都不能访问
// private :只能在类里面访问
// 不加默认为public
ts中的静态方法
//静态方法
class People{
name:string;
constructor(name:string){
// this.name = name;
// console.log(this.sayName());
}
static sayName():string{
//静态方法,实例不能调用,只能通过构造函数调用People.sayName
return this.sex
}
static sex = 'male'; //同样静态属性也一样,只能通过构造函数或静态方法里面获取
}
抽象类
// 抽象类(抽象方法只能出现在抽象类)
// 抽象类感觉就是定个规矩,你继承的子类要遵循这个规矩
abstract class Animal{
//不能实例化 可以用于继承,要求继承的子类必须拥有抽象方法
abstract eat():any; //抽象方法且不能实现,子类继承必须拥有
}
class cat extends Animal{
eat(){
}
}
interface 接口
// interface 接口
// 定义了一个个对象只能有key为name,value为string类型和key为age,value为number类型属性
interface People{
name:string;
age:number
}
//用于对象规定了对象的参数
const p1:People = {
name:'sdsd',
age:23
};
//用于函数规定了入参的类型
function person(people:People){
//定义了接口只能根据People也就是key为name,value为string类型和key为age,value为number
console.log(people.name);
console.log(people.age);
}
//可选属性
interface People2{
//name可以要也可以不要,但是如果传就一定是string
name?:string;
age:number
}
//可以不传
const p2:People2 = {
age:23
};
//用于函数也一样,那么可传可不传
//用于函数规定了入参的类型
function person2(people:People2){
//定义了接口只能根据People也就是key为name,value为string类型和key为age,value为number
console.log(people.name);
console.log(people.age);
}
//另外一种规定函数参数方式
interface Params{
(username:string,password:string,age:number):boolean; //括号里面是入参,后面是返回值
}
interface Params2{
(username:string,password:string,age:number):{username:string,age:number}; //括号里面是入参,后面是返回值
}
const login:Params = (username,password,age) => {
console.log(username);
console.log(password);
console.log(age);
return true
};
const login2:Params2 = (username,password,age) => {
console.log(username);
console.log(password);
console.log(age);
return {username,age}
};
login('ss','sdd',2);
login2('ss','sdd',2);
//也可以定义数组的接口
interface Arr{
[index:number]:number //索引为数字,元素都是数字类型
}
const arr:Arr = [123123,123123,213];
//同数组类似也可用于对象上
interface Obj{
[index:string]:number|string //索引为字符串也就是key,value可以为数字或者字符串
}
const obj:Obj = {
name:'sb',
age:22
};
//对类类型进行约束
interface God{
name:string;
play(name:string):string;
}
class MyGod implements God{
name:'sddd';
constructor(name){
this.name = name;
}
play(name){
return this.name
}
}
interface接口继承
//interface接口继承
interface Animal {
eat(): void
}
interface Person extends Animal {
//接口Person 继承了 Animal
work(): void
}
class People implements Person {
work() {
//根据interface约束了一定要有work
console.log('work');
}
eat() {
//Person 又继承了 Animal所以一定要eat
}
play() {
}
}
class Boy extends People implements Person {
//继承结合接口的约束,因为People引进又了work和eat,所以Boy里面没有也不会报错
}
泛型
//泛型,有时候我们并不知道传入的是什么,但是我们又希望传入传出一致
function getData<T>(value:T):T{
//入参类型是T,出参也是T,
//假如入参是string类型,那么T就是string,出参也是string
return value
}
getData<string>('sdsd'); //T是string类型,出入参都是string
//类的泛型
class MinNum<T>{
list:T[] = [];
add(num:T){
this.list.push(num)
}
min():T{
let minNum:T = this.list[0];
this.list.forEach((item)=>{
if(item<minNum){
minNum = item
}
});
return minNum
}
}
const arr = new MinNum<string>(); //这里可以指定也可以不指定
arr.add('a');
arr.add('b');
arr.add('c');
arr.add('d');
arr.add('e');
console.log(arr.min()); //a
const arr1 = new MinNum<number>(); //这里可以指定也可以不指定
arr1.add(1);
arr1.add(2);
arr1.add(3);
arr1.add(4);
arr1.add(5);
console.log(arr1.min()); //a
//泛型接口
interface config{
<T>(value:T):T //泛型
}
const getData2:config = function (value) {
return value
};
getData2<string>('sdd'); //这里指定了string,入参和出参都只能是string
interface config2<T>{ //也可以放在上面
(value:T):T //泛型
}
const getData3:config2<string> = function (value) { //声明函数的时候声明类型
return value
};
getData3('sdd'); //这里指定了string,入参和出参都只能是string