TypeScript这一片就够了!

一 、简介

TypeScript(简称TS)是一种由微软开发的开源编程语言。它是JavaScript的一个超集,意味着任何有效的JavaScript代码也是有效的TypeScript代码,同时TypeScript在JavaScript的基础上添加了静态类型、接口、类等新特性。使用ts编写代码的时候静态类型校验,更加严谨。

// 1  安装
npm i -g typescript
// 2 在项目文件夹中执行 tsc - init 表示初始化项目
tsc - init

二 、原始类型

ts原始类型就是js基本数据类型这些 (number,string,Boolean,undefined,null,symbol)

	let num: number = 10;
	let str: string = "Hello";
	let bool: boolean = true;
	let n: null = null;
	let u: undefined = undefined;
	let sym: symbol = Symbol("key");
	//在ts中函数没有返回值 函数类型就是void
	function a():void{}  

三 、非原始类型

1 对象

object 不包含基本数据类型 (常用)
Object与 {}定义都一样 效果一样

     //object  不包含基本数据类型 
	let obj:object = {a:1}
	let obj1:object = [1,2]
	let num:object = 1   //报错
	let str:object = 1   //报错
	
	//Object  包含基本数据类型 
	let obj:Object = {a:1}
	let obj1:Object = [1,2]
	let num:Object = 1
	let str:Object = 1

	//与Object 效果一样 包含基本数据类型 
	let obj:{} = {a:1}
	let obj1:{}= [1,2]
	let num:{} = 1
	let str:{} = 1

在这里插入图片描述

2 数组

	// 数组的元素一般数据类型都一致,便于处理
	let arr :number[] = [1,2,3]
	let arr3 :{a:number,b:bumber}[]=[{a:1,b:2},{a:1,b:2}]
	//泛型 类型参数化 (后面详细说)
	let arr1 :Array<number> = [10,20]
	// 元组
	let arr2 :[number,boolean]=[10,true]

3 联合类型 |

	//表示数字或者字符串类型
	let numAndstr:number|string = 1
	//1|'2'在这里的1和'2'是类型 常量 表示numAndstr1的值只能是1|'2'
	let numAndstr1:1|'2'= 1
	
	//表示要么有a属性 或者要么有b属性  并且a属性的值必须是常量1  b属性的值必须是字符串
	let obj:{a:1}|{b:string};  
	obj = {c:1}  //报错
	obj ={a:1}
	obj ={a:2}  //报错
	obj ={ b:'1'}
	obj ={b:1}  //报错

在这里插入图片描述

4 交叉类型 &

	let a:number&string; //不会有任何值满足这个类型  一般不会这么写
	 //& 都 必须有a属性和b属性
	let obj : {a:string}&{b:number}; 
	obj = {a:'1'} // 报错
	obj = {b:1} //报错
	obj = {a:'1',b:1}

在这里插入图片描述

5 接口

接口 :用于自定义类型

	//定义接口类型   ---给对象用
	interface Myitf{
    //属性名:值的类型
    	name:string;
   	 	age:number;
	}
	let obj :Myitf
	obj = {
    	name:'李白',
    	age:21
	}

	// 定义接口类型   ---给数组用
	interface Arrint{
   	 // [idx:number]下标类型:值类型
   		[idx:number]:number|string
	}
	let arr :Arrint
	arr = [1,2,'3']

	// 定义接口  ---给函数用
	interface fnint{
   	 //形参及类型 : 返回值类型
    	(p:string):void
	}
	let fn:fnint = (p:string)=>{

	}
	fn('1')

接口的继承 ,同名 ,缺省 ,只读, 见下方-----------接口

6 联合交叉类型

&与| 交叉使用直接混合双打(& 优先于 |)

	let obj :{name:string}&{age:number} | {pname:string}&{page:number};
	// &优先级高于 | 相当于let({name:string}&{age:number} )| ({pname:string}&{page:number});
	obj={
    	name:'libai',
    	age:18
	}
	obj={
   	 	pname:'libai',
    	page:18
	}

7 ts 函数

// 定义函数参数为字符串 并且返回值为数字
function fn(p:string):number{
        return 1
}
fn('参数为字符串')

// 使用接口定义函数类型
interface fnine {
    // 定义参数为数字  返回值会字符串的函数
    (a:number):string
}
let fn1 :fnine=()=>{
    return '1'
}
// fn1()  //报错 需要传个数字类型参数
fn1(1)

// 使用类型别名定义函数类型
type fntype = (a:number)=>void
let fn2 :fntype =()=>{}
// fn2()  //报错 需要传个数字类型参数
fn2(1)

ts函数参数的写法:

// 代表不传就使用默认值3
function fn (a:number,b:number=3){
    return a+b
}
console.log(fn(1,3));//输出4
console.log(fn(1));//输出4

// 缺省  
function fn1 (a?:number,b:number=3){
    return b
}
console.log(fn(1,3));//输出3
console.log(fn( 1));//输出3

// 剩余参数接受
function fn2 (a:number,b:number=3,...arr:number[]){
   console.log(a,b);//输出1,3
   console.log(arr);//输出[3,4,4,4,]
   
   
}
console.log(fn2(1,3,3,4,4,4,));//输出3

ts中的promise

interface resint{
    code:number,
    data:{a:number,b?:number}[],
    msg:string
}

// promise对象:   p对象名:promise<res的类型>
let p:Promise<resint>  = new Promise((resolve,reject)=>{
    resolve({
        code:0,
        data:[{a:1,b:3},{a:1,}],
        msg:''

    })
})

p.then(res=>{
    if(res.code==0){
        res.data.map(item=>item.a)
    }
})

this指向问题

ts提供了Window类型,window就是这个Window类型的对象

	//在全局上,给Window接口上扩展这个属性
	interface Window{
		myname:string,
	}
	function person (this:Window,name:string){
		//在ts书写中,需要指明this指向   在函数第一形参位置注明
		//Window类型中没有myname这个属性  所以自己通过同名接口来扩展这个属性
		this.name = name
	}
	window.person("")

让this指向自定义对象

interface objint {
    name:string,
    person:(m:string)=>void
}

let obj:objint =  {
    name:'李白',
    person:()=>{}
}

//定义函数的时候,this的类型 必须和调用的时候类型一致
//this:objint|Window这样写好处是可以给多种类型所对应的对象 让this去指向
function person(this:objint,m:string){
    this.name = m
}
obj.person('heiheihei')

四 、any &&unknown

不推荐使用any (不到万不得已不使用,any绕过类型校验)
unknown 一个未知的类型 执行类型校验

	//不报错跳过类型校验
	let a :any ;
	a = 1
	a= 'str'
	a.toFixed(2);//不报错
	
	let b :unknown ;
	b = 1
	b= 'str'
	b.toFixed(2);//报错 有做类型校验  除非上面写number才不会报错
	// 进行类型检查后再赋值
	if (typeof b === 'string') {
    	userName = userInput; // 这里不会报错,因为已经确定了 b 的类型是 string
	}else if (typeof b === 'number'){
		b.toFixed(2)// 这里不会报错,因为已经确定了 b 的类型是 number
	}
	
	

五 、never类型

在 TypeScript 中,never 类型表示那些永远不会发生的值的类型。通常情况下,它用于函数的返回类型,表示该函数永远不会正常返回,或者抛出了异常。
1 函数永远不会返回:

function error(message: string): never {
    throw new Error(message);
}

2 函数中的无限循环:

function infiniteLoop(): never {
    while (true) {
        // 无限循环
    }
}

3 类型保护中的完整性检查:

function throwError(message: string): never {
    throw new Error(message);
}

function checkNumber(x: string | number) {
    if (typeof x === 'string') {
        // 在这里,x 被缩小为 string 类型
        throwError('Not a number: ' + x);
    } else {
        // 在这里,x 被缩小为 number 类型
        return x * 2;
    }
}

六 、接口(interface)

1 继承extends

接口继承的格式,特点是具有父接口的属性类型

	interface NameItf {
    	name:string
	}
	interface AgeItf {
    	age:number
	}
	//  继承上两个接口的属性
	interface personItf extends NameItf,AgeItf{
    	height:number
	}

	let obj:personItf;
	obj = {
    	height:180,
   	 	name:'李白',
    	age:18
	}

在这里插入图片描述

2 同名

接口可以同名,特点是 合并了所用属性

	// 接口同名
	interface Myitf {
    	age:number
	} 
	interface Myitf {
    	name:string
	} 
	let obj :Myitf =  {
    	age:18,
    	name:'李白'
	}

在这里插入图片描述

3 缺省

属性名? 表示这个属性可以缺省 也就是可有可无(定义数据时不写也可以)

	// 接口缺省   

	interface Myitf {
    	age?:number     //属性名? 表示这个属性可以缺省  也就是可有可无
    	name:string
	} 
	//以下两种都不报错
	let obj :Myitf =  {
		//age:18  定义数据时不写也可以
   	 	name:'李白'
	}
	let obj1 :Myitf =  {
   	 	name:'李白',
   	 	age:18
	}

4 只读

接口只读 readonly 表示这个属性只用于读取 不能用于修改

	interface Myitf {
    	age:number     
    	readonly name:string
	} 
	let obj :Myitf =  {
    	name:'李白',
    	age:18
	}
	obj.age =19     //可以修改成功
	// obj.name = '改不了'   //只读属性不可以修改

在这里插入图片描述

七 、类型别名(type)

type 用于自定义类型
与interface的区别:类型别名不支持重复定义 ,接口可以重名
类型别名支持联合交叉类型定义

	//定义一个类型
	type objtype = {a:number&2,b:string}
	let obj:objtype = {
    	a:2,
   	 	b:'1'
	}
	
	interface objint{
    	name:string
	}
	// objint['name']   用类型别名保存接口上的某个属性类型
	type atype = objint['name']
	let str :atype='10'
	
	//类型别名支持联合交叉类型定义
	type color = 'red'|'pink'|'green'|string&{}
	let c :color = 'red'
	c = '字符串'//可以
	c = {}  //报错

八 、枚举(enum)

枚举不是用来定义类型的,是用于列出数据的就,把所有情况列举出来,

	//定义枚举  
	enum StausCode{
		success=200,
		paramsError=400,
		serverErroe =500
	}
	let code:string|number = 400
	if(code ==StausCode.success){
		console.log('成功')
	}else if (code ==StausCode.paramsError){
		console.log('失败,请求参数问题')
	}else if (code ==StausCode.serverErroe ){
		console.log('失败,服务器问题')
	}
	//不写默认加一
	enum StausCode1{
		success,    //0
		paramsError=400,  //400
		serverErroe   //401
	}
	console.log(StausCode1.success,StausCode1.paramsError,StausCode1.serverErroe   )

九、泛型

在 TypeScript 中,泛型(Generics)是一种能让你在定义函数、类、接口等可重用组件时,支持参数化类型的特性。通过泛型,你可以编写与类型无关的代码,以增强代码的灵活性和重用性。

	//等定义的函数参数和返回值一样时
	function fn (n:number|boolean):number|boolean{
		return n
	}
	fn(100)
	fn(true)

	//泛型 可以理解为类型的形参  T是一个标识符  可以自定义  T表示某种类型
	//类型参数化
	function<T> fn1 (n:T):T{
		return n
	}
	fn1<number>(100)
	fn1<boolean>(true)

	//泛型在类型别名上的应用
	//type objtype =  {name:string,age:number,getname:()=>string}
	//let obj:objtype={name:'Libai',age:18,getname(){return 1}}
	//使用泛型
	let STRorNUM= string|number
	type objtype<N,G>={name:N,age:G,getname:()=>N}
	//let obj:objtype<string,number>={name:'Libai',age:18,getname(){return 1}}
	//这里面也可以写类型别名
	let obj:objtype<STRorNUM,STRorNUM>={name:'Libai',age:18,getname(){return 1}}

	//泛型在接口上的应用
	//interface objint {age:number,fn:()=>string}
	//let obj1 :objint = {age:18,fn(){return '字符串'}}
	//使用泛型   B=number为设置默认值   可以设置默认的类型 在使用时可以省略不传
	interface objint<A,B=number> {age:A,fn:()=>B}
	let obj1 :objint<STRorNUM,string> = {age:18,fn(){return '字符串'}}


	//泛型的约束extends
	interface PersonInt<N extends string|number,G>{
		name:N;//需求 :N只能接受字符串或者数字
		getname:()=>G
	}
	//N在这里只可以传string和number  传其他就报错
	let obj :PersonInt<string,number>={
		name:'1',
		getname(){return 1}
	}

十、 类

1 类的定义(类-接口)

	//定义类的同时,相当于定义了相同名称的接口
	class Person{
		//定义属性前,应该先声明这个属性的类型,也可以同时设置默认类型
		age:string='默认名称';
		name:string;
		//使用 new 关键字创建类的实例时,constructor构造函数会自动被调用
		constructor(n:string){
			this.name =n
		}
		getname(){console.log(this.name)}
	}
	let p = new Person('李白')
	console.log(p.name)       //输出    李白
	console.log(p)           //输出 {name:'李白',age:'默认名称',getname:f()}

	//以上这个类相当于下面这个接口
	//interface person  {
    //	name:string;
    //	age:'默认名称';
    //	getname:()=>string
	//}
	let p1:Person = {
		age:'',
		name:'',
		getname(){
			console.log(this.name)
		}
	}

2 类的继承

	//定义父类
	class animal{
    name:string;
    age:number;
    bark(){
        alert('动物在叫!')
    };
    constructor(n:string,a:number){
            this.name=n
            this.age =a
    }
}
// 定义cat类 继承于父类animal 
class cat extends animal{
    // 可以增加自己独有的 属性和方法
    run(){
        console.log('我在跑');       
    };
    // 如果在子类中添加了父类相同的方法   则子类会覆盖掉父类的方法 这种叫做方法重写
    bark(){
        alert('猫在叫!')
        // 在类的方法中super代表当前类的父亲 此处执行父亲的bark方法
        super.bark()
    };
    // 如果在子类中写了构造函数  也会发生方法重写,所以父类中的函数不会执行,所以要通过super()调用父类函数的构造函数
    constructor(name:string,age:number){
        super(name,age)
    }
}

let cat1 = new cat('猫',12)

console.log(cat1);  //{name:'猫',age:12}
console.log(cat1.run());//我在跑
cat1.bark()    //弹出猫在叫       动物再叫

3 类修饰符

class animal {
    //类中,定义的属性 默认的修饰符就是public  public修饰的属性和方法在类内部,外部,子部都可以访问
       // protected  受保护的 类里面  子类都可以访问   类的外面不能访问
    //    private  私有的  只有在当前类访问   子类和类外面都不能访问
    name:string;
    public age:number;
    protected weight:string;
    private run :string
    constructor(n:string,a:number,k:string,r:string){
                    this.name=n
                    this.age =a
                    this.weight = k
                    this.run = r
        }
}
let dog = new animal('狗',12,'12kg','跑步')
console.log(dog.name);
console.log(dog.weight);
console.log(dog.run);

在这里插入图片描述
类的静态属性

	class pre{
		//    静态属性/成员   是给类去用的   只用当前类
		static title:string="title的值"	
	}
	console.log(pre.title)  //title的值
	pre.title = "title修改后的值"
	console.log(pre.title)  //title修改后的值

4 抽象类

// 抽象类  是类的描述   指定一个类的规范,给普通的类去继承

abstract class person{
    abstract name:string;
    abstract getname():string;
    getage(){
            return 11
    }
}
// 普通类继承之后 ,普通类里面就必须定义抽象类里面的抽象属性和抽象方法,
// 抽象类里面的普通方法直接继承,在普通类里可以不用实现
// 普通类
class a extends person{
    name: string="xxx";
    getname(){
        return this.name
    }
}

//抽象类不能被实例化报错
// let p1 = new person()

let m1 =new a()
console.log(m1.getname()) //xxx
console.log(m1.getage())//11

// 定义接口给类使用  implements
interface preint{
    name:string;
    age:number;
    getname:()=>void
}
class m implements preint{
    name:string = "";
    age:number = 0;
    getname(){
        return 11
    }
}
let mm = new m()

十一、 工具类及其他

1 Partial

部分的 表示每个属性都可有可无

interface preint {
    name:string;
    age:number;
}
// 以下都不会报错
//作用  把<>里面这个类型 设置为可缺省
let per1:Partial<preint> = {
    name:'libai'
}
let per2:Partial<preint> = {
    age:16
}
let per3:Partial<preint> = {
    name:'libai',
    age:16
}
let per4 :Partial<preint> = {
   
}

2 Required

必需有的 把<>里面这个类型 设置为不可缺省

	interface preint {
    name:string;
    age?:number;
}

let per5:Required<preint>={
    name:'libai',
    age:18
}

let per6:Required<preint>={
    age:18
}  //报错
let per7:Required<preint>={
    name:'libai',
}   //报错

类型断言:

在 TypeScript 中,类型断言(Type Assertion)是一种告诉编译器某个值的类型的方式。它类似于其他编程语言中的类型转换。通过类型断言,你可以在编译期告诉 TypeScript 编译器某个值的确切类型,并且不需要实际更改该值的结构。

在 TypeScript 中,有两种类型断言的语法:

	//第一种
	let someValue: any = "this is a string";
	let strLength: number = (<string>someValue).length;
	//第二种
	let someValue: any = "this is a string";
	let strLength: number = (someValue as string).length;

类型断言的作用主要有两个方面:

1 类型转换: 当 TypeScript 编译器无法自动推断出某个值的类型时,或者你比编译器更了解某个值的类型时,你可以使用类型断言将该值断言为你期望的类型。

2 解决类型不兼容问题: 在编写泛型代码或者处理联合类型时,有时会遇到类型不兼容的情况。通过类型断言,你可以告诉编译器如何处理这种不兼容,从而使代码能够顺利编译。

需要注意的是,虽然类型断言可以让 TypeScript 编译器认为某个值具有特定的类型,但实际上并不会在运行时对值进行类型转换。因此,在进行类型断言时,务必确保你对值的类型了解清楚,以避免出现运行时错误。

keyof 和typeof和in

keyof

type Person = {
  name: string;
  age: number;
  address: string;
};
//把每一个键值都取出来了 keyof后面一般是接口或者type的对象(Person)   实际上就是:前面的
type PersonKeys = keyof Person; //'name' | 'age' | 'address'  都是常量  

let a:PersonKeys ='name'        //'name' | 'age' | 'address'其中一个

typeof :typeof 是一个类型查询操作符,用于获取一个值的类型。

let x = 10;
let y: typeof x; // 此时 y 的类型为 number

in

//1定义对象的键值可以为所有字符串和数字类型
type pr = {
    [k in string|number]:string
}
let pr1:pr = {
    a:'1',
    2:'2'
}


//2检查对象是否具有指定属性:
interface Person {
    name: string;
    age: number;
}

let person: Person = { name: 'John', age: 30 };

if ('name' in person) {
    console.log('person对象中有name属性');
}

if ('address' in person) {
    console.log('person对象中有address属性'); // 这行不会被执行,因为 person 对象没有 address 属性
}

//3检查指定属性是否存在于对象的原型链中:
class Animal {
    eat(): void {
        console.log('Animal is eating');
    }
}

class Dog extends Animal {
    bark(): void {
        console.log('Dog is barking');
    }
}

let dog = new Dog();

if ('eat' in dog) {
    console.log('Dog can eat');
}

if ('bark' in dog) {
    console.log('Dog can bark');
}
  • 32
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值