一、typescript基础
1.typescript环境搭建
- 自动监听单个ts文件变化
tsc one.ts -w
- 监听所有ts文件变化
tsc --init
会生成一个tsconfig.js文件
执行tsc 转成es6
执行tsc -w
监听所有ts文件变化
-
- 让生成的编译成js的文件放在一个叫js文件夹下面
在tsconfig文件下找到outDir配置成“./js”
- 以上还有一种方法,使用编辑器的插件(vscode、webstorm...)
npm i -g tsc-node
测试环境下直接运行ts文件
2.配置tsconfig.js
3.typescript类型声明基本语法
let str:string = 'hi'
声明参数类型
function add(num1:number,num2:number){}
声明返回值类型
function add(num1:number,num2:number):number{
return 返回数字类型
}
4.ts的基本类型
- number
- boolear
- string
- 数组
声明字符串数组:let arr:string[]=[] *
通过泛型声明字符串数组:let arr:Array<string> = []
- 对象
5.ts特殊类型
- null
let a:null = null 值只有null
- undefined 同上
- any:任意类型相当于关闭ts,不建议使用
- unknow:表示未知类型,一个类型安全的any,不能赋值给其他变量
可以赋值给unknow或ant
如果要赋值给其他类型如下图
- void:表示空,一般用于函数有无返回值
- never:表示永远不会有返回值
6.typescript中对象和函数的类型声明
-
object
1.对象类型声明,数据可有可无写法
2.对象类型声明,有个别数据不是必有向 变量后面加文号?
let obj:{name:string,age:number,sex?:string}
-
function 1.基本函数
声明: function fn(a:number,b:number,c?:number):number{} 调用:fn(1,2)
2.箭头函数声明: const fn:(a:number,b:number) => number fn=(n1,n2) => n1+n2 ------------------------------------ const fn:(a:number,b:number) => number = function(n1,n2):number{retunr n1+n2} -------------------------------------------------------- const fn:(a:number,b:number) => number = (n1,n2) => n1+n2 调用:fn(1,2)
3.匿名函数
7.typescript中的一些运算符号的应用
- 联合类型
- | 相当于 ||
let info:string|number
类型可以是字符串可以是数字
let arr(number | string | boolear)[] = [1,'str']
- & 必须同时满足
let obj:(name:string) & (age:number)
obj = {name:"jack",age:18}
3.字面量进行类型声明
let num:10
值只能是10 相当于是常量let sex:"男" | "女"
值只能是男或者女
- | 相当于 ||
8.typescript中的一些关键字
-
元祖(tuple):固定数组的长度和类型
let arr:[string,number]=["str",1]
二维元祖定义 let arr:[string,number][]=[ ["jack",10], ["rows".20] ]
-
枚举(enum):限制在值得范围内使用枚举比较方便
let state:1 | 2| 3 | 4 这样的使用枚举比较方便
enum state{ famal:0, male :1 } //值会自动往下加1,不指定值默认从0,只读 //调用 console.log(state.famal)
-
类型的别名
type mystate = 1|2|3|4|5 let state:mystate // state = 1 state = 8 //报错 //函数别名 type myvar = string | number | blooean function(a:myvar,b:myvar,c:myvar){ } //定义 type myfun = (a:number,b:number) => number //使用 let fun:myfun = (a,b) => a * b //调用 fun(10,20) //对象别名 type myobj = {name:string,age:number} let person:myobj={name:'jack',age:10}
类型断言(强制类型转换)
-
类型缩小
function demo (n:number|string){ console.log(n.lenght) //会出现报错 number没有length属性 let len:number if(typeof n == "string"){ len = n.lenght } console.log(len) }
-
类型断言
function demo (n:number|string){ console.log(n.lenght) //会出现报错 number没有length属性 let len:number //第一种 len = (<string>:n).length //第二种 len = (n as string).length console.log(len) }
-
as const 应用:相当于转换成字面值变量而不是常量,根据具体的值转换
//常量和字面量值的区别 //常量不能复制,字面量值可以赋值但是只能是哪一个值 const abc = "abc" abc = "abc": //报错 //字面量 let abc:"abc"="abc" abc="abc" //数组 let arr1 = ["www",12] as const //变成只读的元祖 let arr2 = <const>["www",12] //同上 建议使用上面那种 //对象 let user = { name :“Jack”, age :18 }as const //变成只读的obj //在解构中使用as const function ew (){ let str = "www.baidu" let fun = (a:number,b:number):number => a+b return [str,fun] } //let [nstr,nfun] = ew() //直接调用 nfun(1,2)会报错 有可能是字符串 //第一种 let [nstr,nfun] = ew() as [string,function] //第二种 let [nstr,nfun] = ew() //nfun as Function(1,2) nfun as ((a:number,b:number) => number)(1,2) //第三种 function ew (){ let str = "www.baidu" let fun = (a:number,b:number):number => a+b // return [str,fun] as [string,function] //return [str,fun] as [typeof str,typeof fun] return [str,fun] as const //推荐 }
-
非空断言 !dom断言
二、typescript进阶
1.函数式编程
- 函数类型
//(n,number,m:number) => number 这不是箭头函数 这是声明函数参数类型,和返回值类型
//声明函数类型
type myfun = (n:number,m:number) => number
//let myfun = function(a,b){}
let fun:(n,number,m:number) => number = function(a,b){
retunr a+b
}
let fun2:myfun = (a,b) => a+b
- 参数为回调函数
type myfun = (n:number,m:number) => number
function calc(a:number,b:number,fn:myfun){
return fn(a,b)
}
let result:number = calc(10,20,(a,b) => a + b)
console.log(result)
let result2:number = calc(10,20,function(a,b){return a * b})
console.log(result2)
- 函数参数灵活用法
//参数的可选类型 ? === undefined 可以传undefined 第一个不能是可选
type myfun = (n:number,m?:number) => number
const fun:myfun = function(a,b){
retunr 10
}
fun(1)
//参数的默认值
const fun = function(a:number = 1,b:number=2){
console.log(a,b)
}
fun()
//函数剩余参数
//扩展运算符
function fn(..args:any[]){
//function fn(..args:number[]){ 限制number类型就只能传number
//function fn(a:number,b:number,...args:number[]){
// console.log(args) // [1,2,str]
console.log(a) //1
console.log(b) //2
//console.log(args) [3,str]
}
fn(1,2,"str")
fn(1,2,3,"str")
//
- 函数重载(ts新加的功能,es6,script没有)
//解决方法名相同,参数类型,参数个数,参数顺序不同,函数返回值不确定 === 重载
//声明
let add(a:number,b:number):number
let add(a:string,b:string):string
//实现
function add(a:any,b:any):any{
return a + b
}
//调用
add(1,2)
add("www","com")
2.面向对象编程思想
对象的思想、语法:
类,接口...声明
三大特性:封装,继承,多态
3.类(es6中类的用法+ts增强)
- 类的概念
- 类的声明
class Person{
name : string;
age:number;
//初始化值。创建的时候给值
constructor(name:string,age:number = 0){
this.name = name;
this.age = age;
}
say(){
console.log(this.name +"说话")
}
}
const p1 = new Person()
pq.say()
- 类的继承(扩展):代码的可复用性
class Person{
name:string;
age:number;
constructor(name:string,age:number = 0){
this.name = name;
this.age = age;
}
say(){
console.log(this.name +"说话")
}
}
class Student extents Person{
school:string;
constructor(name:string,age:number,school:string){
super(name,age);
this.school = school;
}
stydy(){
console.log("在" + this.scool + "学习")
}
}
const s1 = new Student("jack",18,"元时代");
s1.say()
s1.study()
class Teacher extents Person{
price:number;
constructor(name:string,age:number,school:string,price:number){
super(name,age,school);
this.price = price;
}
}
const t1 = new Student("jack",18,"元时代",2200);
s1.say()
s1.study()
console.log(s1.price)
//方法的重写 == 方法名相同 会覆盖父类的方法
//方法的扩展
class Teacher extents Person{
price:number;
constructor(name:string,age:number,school:string,price:number){
super(name,age,school);
this.price = price;
}
stydy(){
super.stydy()
console.log("在" + this.scool + "备课")
}
}
const t1 = new Teacher("jack",18,"元时代",2200);
t1.study() // 在元时代学习 在元时代备课
- 类成员的访问修饰符(封装)
//public:默认的、缺省的,类的内部、类的外部、子类中都可访问
//private:私有的,只能在类的内部
//protected:受保护的,只能在类的内部和子类内部使用
//readonly:只读的,类内部、类外部都可访问 == const
class Person{
//public name:string;
name:string;
age:number;
//public constructor(name:string,age:number = 0){
constructor(name:string,age:number = 0){
this.name = name;
this.age = age;
}
//public say(){
say(){
console.log(this.name +"说话")
}
}
- 封装(ts提供了存取器)
//封装类的方法
class Person{
name:string;
constructor(name:string){
this.name = name;
}
run(){
this.left()
this.right()
}
private left(){
console.log("迈左腿")
}
private right(){
console.log("迈右腿")
}
}
//封装类的属性
class Person{
name:string;
private _age : number;
constructor(name:string,age:number){
this._age = name;
}
//ts提供的存取器
set age(age:number){
this._age = age
}
get age(){
return this._age
}
// ==========================
//两者区别:调用不一样
setAge(age:number){
this._age = age
}
getAge(){
return this._age
}
}
const p1 = new Person("jack",20);
//ts提供的存取器
console.log(p1.age)
//普通方法
console.log(p1.getAge())
- 静态static的应用
静态成员不在对象中,在类中存在,通过类名调用
在静态方法里面只能访问静态成员 this.静态成员
在静态方法里面this代表类
在非静态方法里面访问静态成员不能使用this需要使用类名.静态成员
static的目的:想让一个类的内部成员,让所有对象,以及类的内部外部直接用类名访问就声明成静态成员,静态方法
class Person{
static name:string = "";
age:number=18;
static say(){
console.log(123)
}
}
const p1 = new Person("jack",18);
p1.name //会报错
Person.name
4.抽象类与接口
- 抽象类(abstract)
abstract class Person{
name:string = "jack";
static say(){
console.log(this.name)
}
abstract run():void //抽象方法:没有方法体的方法就是抽象方法,只要有一个抽象方法这个类就属于抽象类
}
//const p1 = new Person() 报错
class Demo extends Person{
//重写抽象方法,让子类不是抽象类就可以通过实例化对象进行访问
run(){
console.log(11)
}
}
⑴:抽象类不能够被实例化,意味着抽象类中的不管是不是抽象方法都是不能调用
⑵:抽象类作用:约束子类必须有抽象方法的实现
⑶:抽象类是一个特殊的类,结合多态使用
- 接口(interface)
interface One{
//属性只能是共有的
hello:string;
//say(name:string):void
say:(name:string) => viod
//只写结构让子类去实现
}
//声明接口
interface Two{
foo():void
}
//接口继承/两种方式
interface Three extends One,Two{
far():void
}
//抽象类实现接口
abstract class Three extends One{
}
//实现接口(implement)
//class Four extends Demo implement Three{
class Four implement Three{
hello:string = "hello"
far(){}
foo(){}
say(){}
}
⑴:接口又是一个特殊的抽象类
⑵:接口里面不能有普通的成员方法
⑶:成员方法必须是共有的
⑷:接口里面所有的方法都是抽象方法
⑸:接口里面所有的属性和方法都是抽象的可以没有初始值
⑹:一个接口可以继承多个子接口
⑺:可以继承一个类在实现多个接口
- 多态
//用接口来规范USB
interface USB {
start():void;
run():void;
end():void;
}
//调用接口
function demo(u:USB){
u.start();
u.run();
u.end();
}
//实现接口
class shubiao implement USB{
start(){
console.log("shubiao开始")
}
run(){
console.log("shubiao运行")
}
end(){
console.log("shubiao结束")
}
}
demo(new shubiao())
//demo({
// start(){},
// run(){},
// end(){}
//})
⑴:必须有继承关系
⑵:将子类对象赋给父类的应用,调用父类的方法其实就是在执行子类中具体的方法
- 面向对象接口的应用
Ⅰ:声明对象的几种方式
//类类型
class Person{
name:string = "";
age:number= 0
}
const p:Person = new Person()
const p1:Person = {
name:"jack",
age:10
}
const p2 = new Person()
//
const o1:{
name:string,
age : number
}={
name :"abc",
age:10
}
//类型别名方式
type myObj = {name:string,age:number}
o2:myObj = {
name:"edu",
age:18
}
//接口方式
interface One{
name:string,
age:number
}
o3:One={
name:"abc",
age:19
}
创建对象接口和类型别名方式的区别
1.接口可以继承
2.接口可以重名,重名自动合并
只要是对象都使用接口方式interface
3.在接口中可以声明只读属性 readonly,可选属性在name ? : string
4.接口中声明任意属性interface list {[item:number]:string} key是数字类型value是字符串类型的 const l1:list = {1:"one" ...}
5.泛型(类型参数化)
- 类型参数化:在声明的时候不指定类型,在调用的时候决定
function fun<T>(arg1:T,arg2:T,arg3:T):T{
//function fun<T,W,O>(arg1:T,arg2:W,arg3:O):T{
return arg2
}
fun<number,string,{name:string}>(1,2,{name:"ab"})
- 泛型灵活运用
1.泛型参数的默认类型
function fun<T = number>(arg:T){
}
fun<string>("abc")
2.泛型约束
interface ILength{
length:number
}
function fun<T extends ILength>(arg:T):number{
return arg.length
}
//fun(10) 报错数字没有length
fun("abc")
fun([1,2,3])
fun({name:"jack",lenght:10})
3.泛型接口
interface IPerson<T1=string,T2=number>{
name:T1,
sex:T2
}
cosnt p:IPerson<string,number> = {
name:"jack",
sex:10
}
4.泛型类
class Person<T1,T2>{
name:T1;
sex:T2
constructor(name:T1,sex:T2){
this.name = name
this.sex = sex
}
}
//const p1 = new Person("jack",10) 调用自动推断
//const p2 = new Person<string,number>("jack",10)//指定类型
const p2:IPerson<string,number> = new Person("jack",10)//指定类型
//回顾数组
1、普通字符串数组
const arr:string[] = ["a","b"]
2.通过泛型声明数组
const arr2::Array<number> = [1,2,3]
三、开发工程化
1.使用webpack打包TS文件(vue、react、vite...)
2.typescript命名空间(namespace)
namespace One{
export let str:string; //要想在外面使用就得导出
console.log(str)
}
console.log(One.str)
namespace Two{
let str:string;
console.log(str)
}
console.log(Two.str) //报错没有导出