Typescript
环境安装
node.js
全局安装Typescript环境(基础类型)
安装命令
npm i typescript -g
typeScript试用及运行方法
1.命令tsc文件名字
新建ts文件1.ts
使用tsc 1.ts进行下转换(node环境无法运行ts代码),转换完之后为同级目录
2.监听编译tsc 1.ts -w,改变文件时保存就会编译
3.直接执行tsc,tsc-w编译所有的ts文件
需要配置文件ts.config.json,使用tsc --init执行生成
4.然后重开一个终端,使用node.js运行
(任意类型)— 需要安装3个库
1.Windows Powershell 输入npm i ts-node -g
2.打开项目,终端输入npm init -y生成package.json文件
3.生成完之后需要生成一个声明文件npm i @types/node -D
在项目1.ts终端输入ts-node 1.ts进行编译
数据类型
any 任意类型 unknown 不知道的类型
- top type 顶级类型 any unknown
- Object
- Number String Boolean
- number string boolean
- 1 ‘小满’ false
- never
unknown 只能赋值给自身 或者any
unknown没有办法读任何属性,方法也不可以调用
unknown比any更加安全
let a1:object='123'
let a2:obeject=123
let a3:object=false
//以上都是错误的 原始类型
let a4:object=[]
let a5:object={}
let a6:object=()=>123
//以上为正确的
//常用于泛型约束
接口和数据类型
在typescript中,我们定义对象要用关键字interface(接口),使用interface来定义一种约束,让数据的结构满足约束的格式,定义的方法如下:
//interface 重名->重合
//interface 任意key
//interface ? readonly
//interface 接口继承
//interface 定义函数类型
//不能多属性,也不能少属性
interface Axx extends B{//使用exttends使B继承A
name:string
age?:number//可以有,可以没有
[propName:string]:any//使用索引签名去定义其他的任意属性
//名字第一个字母要大写
readonly cb:()=>boolean//只读属性,不让修改-使用修饰符readonly
readonly id:number
}
interface Bxx{
xxx:string
}
let a:Axx={
name:"小满",
age:88,
a:1,
b:2,
c:3,
ch:()=>{return true},
id:1,
xxx:'xxx'
}
/*const fn=function(){
//如何定义一个function的类型
}*/
interface Fn{
(name:string):number[]
}
const fn:Fn=function(name:string){
return [1]
}//将参数和返回值进行了约束
数组类型
-
number[ ]
let arr1:number[]=[1,2,3,4,5]
let arr2:boolean[]=[true,false,true]
-
定义数组的普通类型Array< boolean >
let arr1:Array< boolean > = [true,false]
-
定义对象数组使用Interface
interface X{ name:string } let arr:X[]=[{name:"小满"},{name:"胡萝卜"}
-
定义二维数组
let arr1:number[ ] [ ] =[[1],[2],[3]]
let arr1:Array<Array< boolean > > =[[1],[2],[3]]
- 定义大杂烩数组
let arr3:any[ ]=[1,‘sadsad’,true,{ }]
let arr4:[number,string,boolean,{ }]=[1,‘sadsad’,true,{ }]
function a(...args:any[]){
console.log(args)
}
a(1,2,3)
函数类型
-
函数定义类型和返回值||箭头函数定义类型和返回值
-
函数默认的参数|函数可选参数
function add1(a:number=10,b:number=20):number{ return a+b }//函数参数的默认值 // const add=(a:number,b:number):number=>a+b console.log(add1(1))//传了值则用传的值,没传的用默认值,结果为1+20=21 function add2(a:number=10,b?:number):number{ return a+b//通过?表示该参数为可选参数,a:number=“我是默认值” }//默认值和可选参数(你可以传也可以不传)不能一块使用 // const add=(a:number,b:number):number=>a+b console.log(add2(1))//结果为1+undefined=NaN
-
函数this类型
interface Obj{ user:number[] add:(this:Obj,num:number)=>void//无返回值的函数 } //ts 可以定义this的类型,在js中无法使用 必须使第一个参数定义this的类型 let obj:Obj={ user:[1,2,3], add:(this:Obj,num:number){ this.user.push(num) }, } obj.add(4)
-
接口定义函数
//定义参数num和num2的类型,后面定义返回值的类型 interface Add{ (num:number,num2:number):number } const fn:Add=(num:number,num2:number):number=>{ return num+num2 } console.log(fn(5,5)) //通过interface定义函数参数为对象 interface User{ name:string age:number } function getUserInfo(user:User):User{ return user } console.log(getUserInfo({name:"小满",age:18}))
-
定义剩余参数
const fn=(array:number[],...items:any[])=>{ console.log(array,items) return items } let a:number[]=[1,2,3] fn(a,'4','5','6')//输出[1,2,3] ['4','5','6']
-
函数重载
重载是方法名字相同,而参数不同,返回类型可以相同也可以不用。
如果参数类型不同,则参数类型应设置为any
参数数量不同你可以将不同的参数设置为可选
let user:number[]=[1,2,3]
function findNum(add:number[]):number[]//如果传的使一个number类型的数组那就做添加
function findNum(id:number):number[]//如果传入了id就是单个查询
function findNum():number[]//如果没有传入东西就是查询全部
function findNum(ids?:number | number[]):number[]{//传入的参数ids可以传的是单个数字,或者数字类型的数组,或者不传
if(typeof ids=='number'){//传入一个number类型的数
return user.filter(v=>v==ids)
}
else if(Array.isArray(ids)){//传入的为number类型的数组
user.push(...ids)
return user
}
else{//传入的为空
return user
}
}//实现上述三种功能的函数
console.log(findNum())//[1,2,3]
console.log(findNum(3))//[3]
console.log(findNum([4,5,6]))//[1,2,3,4,5,6]
联合类型|类型断言|交叉类型
联合类型
//例如我们的手机号通常是13XXXXXXX 为数字类型 这时候产品说需要支持座机
//所以我们就可以使用联合类型支持座机字符串
let myPhone:number|string='010-820'
//这样写是会报错的因为我们的联合类型只有数字和字符串并没有布尔值
let myPhone:number|string=true
let fn=function(type:number|boolean):boolean{
return !!type//强转
}
let result = fn(1)
console.log(result)
交叉类型
多种类型的集合,联合对象将具有所联合类型的所有成员
interface People{
name:string
age:number
}
interface Man{
sex:number
}
const xiaoman=(man:People & Man):void =>{
console.log(man);
}
xiaoman({
name:"xiaoman",
age:108,
sex:1
})
类型断言
语法:值 as 类型 或 <类型>值 value as string < string >value
let fn1=function(num:number|string):void{
console.log((num as string).length)
console.log((<string>num).length)
}
fn1(12345)
interface A {
run: string
}
interface B {
build: string
}
const fn = (type: A | B): string => {
return type.run
}
//这样写是有警告的应为B的接口上面是没有定义run这个属性的
interface A {
run: string
}
interface B {
build: string
}
const fn = (type: A | B): string => {
return (type as A).run
//return (<A>type).run
}
//可以使用类型断言来推断他传入的是A接口的值
注意:类型断言只能“欺骗”TypeScript编译器,无法避免运行时的错误
滥用类型断言反而可能导致运行时错误
使用any临时断言
window.abc=123
//这样写会报错因为window没有abc这个东西
(window as any).abc = 123
//可以使用any临时断言在 any 类型的变量上,访问任何属性都是允许的
as const
是对字面值的断言,与const直接定义常量是有区别的
如果是普通类型跟直接const 声明是一样的
const names = '小满'
names = 'aa' //无法修改
let names2 = '小满' as const
names2 = 'aa' //无法修改
// 数组
let a1 = [10, 20] as const;
const a2 = [10, 20];
a1.unshift(30); // 错误,此时已经断言字面量为[10, 20],数据无法做任何修改
a2.unshift(30); // 通过,没有修改指针
类型断言是不具影响力的
在下面的例子中,将 something 断言为 boolean 虽然可以通过编译,但是并没有什么用 并不会影响结果, 因为编译过程中会删除类型断言
function toBoolean(something: any): boolean {
return something as boolean;
}
toBoolean(1);
// 返回值为 1
内置对象&代码雨
ECMAScript 的内置对象
Boolean
、Number、string
、RegExp
、Date
、Error
let b: Boolean = new Boolean(1)
console.log(b)
let n: Number = new Number(true)
console.log(n)
let s: String = new String('哔哩哔哩关注小满zs')
console.log(s)
let d: Date = new Date()
console.log(d)
let r: RegExp = /^1/
console.log(r)
let e: Error = new Error("error!")
console.log(e)
DOM和BOM的内置对象
Document、HTMLElement、Event、NodeList等
//HTML(元素名称)Element HTMLElement
let div1:HTMLDivElement=document.querySelector('div')
let div:HTMLElement = document.querySelector('div') as HTMLDivElement
let div3:NodeList=document.querySelectorAll('footer')
let div4:NodeListOf<HTMLDivElement|HTMLLabelElement>=document.querySelectorAll('div footer')
div3.forEach
let local:Storage=localStorage
let lo:Location=location
let promise:Promise<string>=new Promise((r)=>r('小满'))
let cookie:string=document.cookie
document.addEventListener('click', function (e: MouseEvent){
})
定义Promise
如果我们不指定返回的类型TS是推断不出来返回的是什么类型
指定返回的类型,语法规则:Promise<类型>
let promise:Promise<string>=new Promise((r)=>r('小满'))
function promise():Promise<number>{
return new Promise<number>((resolve,reject)=>{
resolve(1)
})
}
promise().then(res=>{
console.log(res)
})
代码雨案例
let canvas = document.querySelector('#canvas') as HTMLCanvasElement
let ctx = canvas.getContext('2d') as CanvasRenderingContext2D
canvas.height = screen.availHeight; //可视区域的高度
canvas.width = screen.availWidth; //可视区域的宽度
let str: string[] = 'XMZSWSSBXMZSWSSBXMZSWSSBXMZSWSSBXMZSWSSB'.split('')
let Arr = Array(Math.ceil(canvas.width / 10)).fill(0) //获取宽度例如1920 / 10 192
console.log(Arr);
const rain = () => {
ctx.fillStyle = 'rgba(0,0,0,0.05)'//填充背景颜色
ctx.fillRect(0, 0, canvas.width, canvas.height)//背景
ctx.fillStyle = "#0f0"; //文字颜色
Arr.forEach((item, index) => {
ctx.fillText(str[ Math.floor(Math.random() * str.length) ], index * 10, item + 10)
Arr[index] = item >= canvas.height || item > 10000 * Math.random() ? 0 : item + 10; //添加随机数让字符随机出现不至于那么平整
})
console.log(Arr);
}
setInterval(rain, 40)
Class类
//定义类
class Person{
construtor(){
}
run(){
}
}
1.在Ts如何定义类(变量)
class Persom{
name:string
age:number=0//定义了变量不用也会报错,通常给个默认值或者赋值
//TypeScript是不允许直接在constructor定义变量的,需要在constructor上面先声明
constructor(name:string,age:number){
this.name=name
this.age=age
}
}
2.类的修饰符
总共有三个public private protected
class Person{
public name:string
private age:number=0
protected some:any
constructor(name:string,age:number,some:any){
this.name=name
this.age=age
this.some=some
}
}
let xiaoman=new Person('小满',18,1)//自己定义的一个类Person
console.log(xiaoman.name)
console.log(xiaoman.age) //属性age为私有属性 只能在类Person中访问
console.log(xiaoman.some)//属性some受保护 只能在类Person及其子类中访问
使用public修饰符 可以让你定义的变量既可以内部访问也可以外部访问 如果不写默认就是public
使用private修饰符 代表定义的变量私有的只能在内部访问 不能再外部访问
3.static静态属性和静态方法
class Person{
public name:string
private age:number=0
protected some:any
static nb:string
constructor(name:string,age:number,some:any){
this.name=name
this.age=age
this.some=some
this.nb//我们利用stactic定义的属性 不可以通过this去访问只能通过类名去调用
}
static run(){
return console.log(this.name)
} //static静态函数同样不能通过this去调用 也是通过类名去调用
static aaa(){
return 'aaaaadsd'
}//注意:如果两个函数都是static静态是可以通过this互相调用
}
Person.nb
4.interface定义类(类型约束implements||继承extends)
ts interface 定义类 使用关键词 implements 后面跟interface的名字,多个用逗号隔开 继承还是用extends
interface PersonClass {
get(type: boolean): boolean
}
interface PersonClass2{
set():void,
asd:string
}
class A {
name: string
constructor() {
this.name = "123"
}
}
class Person extends A implements PersonClass,PersonClass2 {
asd: string
constructor() {
super()
this.asd = '123'
}
get(type:boolean) {
return type
}
set () {
}
}
抽象类
应用场景如果你写的类实例化之后毫无用处此时我可以把他定义为抽象类
或者你也可以把他作为一个基类-> 通过继承一个派生类去实现基类的一些方法
我们看例子
下面这段代码会报错抽象类无法被实例化
abstract class A {
public name:string
}
new A()
例子2
我们在A类定义了 getName 抽象方法但为实现
我们B类实现了A定义的抽象方法 如不实现就不报错 我们定义的抽象方法必须在派生类实现
abstract class A{
name:string
constructor(name:string){
this.name=name;
}
print():string{
return this.name
}
abstract getName():string
}
class B extends A{
constructor(){
super('小满')
}
getName():string{
return this.name
}
}
let b=new B();
console.log(b.getName())//小满
//基类 抽象类
//abstract 所定义的抽象类
//abstract所定义得方法 都只能描述不能进行一个实现
abstract class Vue{
name:string
constructor(name?:string){
this.name=name;
}
getName(){
return this.name
}
abstract init(name:string):void
}
//new Vue() 报错
//抽象类无法被实例化
class React extends Vue{//非抽象类“React"不会实现继承自"Vue"类的抽象成员“init"
constructor(){
super('df')
}
init(name: string): void {
}
setName(name:string){
this.name=name//在抽象类已经定义过了,在派生类不用二次定义
//派生类可以实例化
}
}
const react=new React()
react.setName('小满-丝袜')
console.log(react.getName())
//虚拟dom 简单版
Class Dom{
//创建节点的方法
createElement(el:string){
return document.createElement(el)
}
//填充文本的方法
setText(el:HTMLElement,text:string|null){
el.textContext=text
}
//渲染函数
render(date:Vnode){
let root=this.createElement(date.tag){
if(date.children&&Array.isArray(data.children)){
data.children.forEach(item=>{
let child=this.render(item)
root.appendChild(child)
})
} else{
this.setText(root,data,text)
}
}
}
}
Class Vue extends Dom implements VueCls{
options:Options
constructor(options:Option){
super()//必须放在最上面
}
this.render(date)
}