ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

typescript基础学习

2021-11-06 23:34:00  阅读:176  来源: 互联网

标签:function typescript console name 基础 学习 any string log


一:typescript介绍和环境搭建

1.typescript介绍

TS是属于JavaScript的超集,可以编译成纯JavaScript,TS新增了许多特性,例如数据类型、类、继承以及接口等。

2,typescript环境搭建

i.项目环境搭建

安装node.js=>全局按照typescript:npm i -g typescript

ii.编写一个ts文件并编译

编写一个.ts文件=>命令行tsc b.ts=>编译成一个JavaScript文件。

iii.vscode配置自动编译

在当前项目执行指令

tsc --init

在项目根目录生成一个tsconfig.json文件:

 

自动编译,选择终端>运行任务>监视typescript。之后每次文件一保存,就会自动编译。

二:typescript的数据类型

typescript的数据类型主要有:

布尔类型(boolean)

数字类型(number)

字符串类型(string)

数组类型(array)

元组类型(tuple)

枚举类型(enum)

任意类型(any)

null和undefined

void类型

never类型

格式:let 变量:类型=变量值

1,boolean类型

let flag:boolean=[false|true]

2.数字类型

let num:number=12

let float:number=12.12

3.字符串类型

let str:string='hello world'

4.数组类型

let array:number[]=[1,2] let str:string[]=['1','2']

泛型方式

let arr:Array<string>=['we','eo']

5.元组类型

元组类型是数组类型的一种,可以指定数组中每个元素的类型

let tup:[string,number,boolean]=['we',21,false]

6.枚举类型

定义:

enum 枚举变量名{

      枚举类名=枚举值,

      枚举类名1=枚举值1,

       .........

}

使用

var  变量:枚举类型=枚举变量名.枚举名

var 变量名=枚举变量名.枚举名

 

enum flag{
   success=1,
   errorM=-1
}
var F:flag=flag.success
//var F=flag.success
console.log(F);

 单枚举项都为number类型的时候(默认为number)如果不赋值,打印的将是元素的索引值,如果元素的前面的元素有值,则改元素打印的值为前面元素加1

 7.任意类型(any)

在我们获取dom节点的时候,不知道应该取什么类型,就可以使用any类型

let dom:any=document.getElementById('app')

 

8.null和undefined

i.undefined

在typescript必须指定其变量类型,要不然会报错,这时候我们只定义不赋值的时候,在使用变量的时候变量也会报错

这时候就提供了undefined解决这个问题,指定变量为其他类型或者undefined,这时不赋值就不会报错了。

ii.null

表示为空,和undefined有点类似,一个变量可能是空或者undefined

let num:number|undefined|null

iii.void类型

表示定义无返回值的方法

function fn():void{
    console.log('q'); 
}

相对的可以指定返回值的类型

function fn():number{
    return 1
}

 

9.never类型

never表示其他类型的(包括null和underfined)子类型,表示从未出现过的值,是一个隐含的类型。主要体现在

never类型只能被never类型赋值

let num:number; num=12

如上声明num类型的时候,该变量赋值时只能赋一个number类型的值。如果不是会报错

let nev:never
nev:(()=>{
throw new Error('错误')
})()

真正的写法如上,但是不常用,一般使用any或者多类型定义来解决。

let a:null|undefined|number|string|boolean

三.typescript函数

1,typescript函数的定义

有返回值

function name(params:type):type {
    return paramType
}
或
let name=function (params:type):type {
    return paramType
}

无返回值

function name(params:type):void {
   
}
或
let name=function (params:type):void {
  
}

四.typescript的类、接口

对象:具体的,实际的,代表一个事物,建一个对象的属性和行为封装在一起,就构成一个类。

 

1.typescript定义类

使用的是es6的新特性:关键字class

class Person{
    
}

2.类中的属性

类中有三大属性:变量、构造方法、方法。

其中变量又可以分为:公共变量、私有变量、保护变量

class Person{
    public name:string;//如果是公共方法,public可以省略
    constructor(name:string){
        this.name=name
    }
    eat(){
        console.log('普通方法'); 
    }
}

i.实例化类

var person=new Person('小明')

调用:

person.eat() person.name//使用public修饰,可以直接访问,如果使用private修饰,只能向外提供公共的访问方法get/set方法

ii.private关键字:静态变量

特点:静态变量不可以直接调用,只能通过提供对外访问方法,

好处:保证了类中变量的安全性,不使外部直接访问到。

class Person{
    private name:string;
    constructor(name:string){
        this.name=name
    }
    eat(){
        console.log('普通方法');
        
    }
    getName(){
        return this.name
    }
    setName(name:string){
        this.name=name
    }
}
var p =new person()

直接通过:p.name是无法访问该变量,只能通过getName/setName间接访问和修改

p.getName()

p.setName("小红")

 3.类实行继承:extends

继承只能继承父类的公共属性,私有属性无法继承。

继承只能单继承,不能多继承。

类只能单继承。

4.类的修饰符

typescript提供了三个修饰符:public(保护)、protected(保护)、private(私有)

默认是public,定义时可以省略。

protected:被修饰的属性只能在继承体系内使用。

private:定义的属性只能在该类使用。

5.类的静态属性和静态方法:关键字static

在es5中,直接通过构造函数的方式添加方法和属性,叫做静态方法和静态属性

function Person(){
   name:"xiaozhi"
   setName:()=>{
    console.log("实例方法")
   }
}
Person.age="12"
Person.setAge=function(){
    console.log('静态方法');
}
//静态调用
Person.setAge()
Person.age
//实例调用
var p=new Person()
p.setName()
p.name

typescript中的静态方法和静态实例

静态方法和属性和实例方法和属性的区别

静态方法和实例可以直接通过类名调用,实例方法和属性需要使用实例化类名调用。

静态方法和属性不会随着类的调用后而消失,实例方法和属性则会。

定义静态属性和静态方法

 class Person{
    static name2='xiaozhi';
    static  run(){
        console.log("go"); 
    }
}
Person.name2
Person.run()

6.类的多态

多态:同一个事物表现出不同的状态表示多态。多态中的父类方法值定义不实现功能。

例如:水有固态、液态和气态三种状态,那么父类就是水,而子类就是不同状态的水。

那就实现以下这个代码吧

class water{
     name:string;
    constructor(name:string){
        this.name=name
    }
    waterState(){}
}
class Gutai extends water{
    constructor(name:string){
        super(name)
    }
    waterState(){
        console.log("我是"+this.name+"水"); 
    }
}
class Yetai extends water{
    constructor(name:string){
        super(name)
    }
    waterState(){
        console.log("我是"+this.name+"水"); 
    }
}
class Qitai extends water{
    constructor(name:string){
        super(name)
    }
    waterState(){
        console.log("我是"+this.name+"水"); 
    }
}
var gutai=new Gutai('固态')
gutai.waterState()
var yetai=new Yetai('液态')
yetai.waterState()
var qitai=new Qitai('气态')
qitai.waterState()

7.抽象类:abstract

抽象类就是类的基类

举个例子:人都要吃饭,都要睡觉,都要呼吸,将吃饭睡觉呼吸提取出来放到一个类,并有abstract修饰,就变成一个抽象类了,只是抽象类只提供行为不执行行为,你吃什么饭,睡觉睡得怎样呼吸快慢抽象类不管,抽象类只管你要是继承我,这些行为必须得有。

抽象类有一下特性:

抽象类不能被实例化,

抽象类的成员可以不是抽象成员,但是有抽象成员的类必须是抽象类。

子类继承抽象类必须重写抽象类的抽象方法。

子类可以是一个抽象类,表示该子类必须有这个行为。

总结一下:抽象类就是提供行为而不执行行为的类【人是一个抽象类,都得吃饭,小米是一个具体类(也可以是抽象子类,这个看下面)吃什么不管,你想吃啥就吃啥,但是必须得有吃的这个行为】。

abstract class Person{
    abstract eat():any;
}
class Xiaoming extends Person{
     food:string;
     constructor(food:string){
         super()
         this.food=food
     }
      eat(){
          console.log("小明会吃,正在吃"+this.food);
          
      }
}
var xiaoming=new Xiaoming("窝窝头")
xiaoming.eat()

抽象类的成员:

成员变量:既可以是变量也可以常量,当不能用abstract修饰(修饰就无法初始化变量了)

成员方法:既可以是一般方法也可以是抽象方法,一般方法无需重写(想要访问抽象类的变量最好重修)

构造函数:有,作用是初始化成员变量。

abstract class Person{
     food:string;
    constructor(food:string){
        this.food=food
    }
    abstract eat():any;
    run(){
        console.log("小明边跑边吃着"+this.food);
        
    }
}
class Xiaoming extends Person{
     constructor(food:string){
         super(food)
     }
      eat(){
          console.log("小明会吃,正在吃"+this.food);  
      }
}
var xiaoming=new Xiaoming("大白菜")
xiaoming.eat()
xiaoming.run()

五.接口:interface

typescript中接口就是对json数据进行约束或者对类进行拓展,约束json数据的时候主要是对对象数据进行约束,规范对象数据的内部数据格式必须和接口一致。

1.接口的约束作用

a.接口对json数据进行拓展(即对象)

 

interface PersonIf{
    name:string;
    age:number;
    sex:boolean
}
function getPerson(obj:PersonIf):string{
    return ''
}
var obejct={
    name:'小孩',
    age:18,
    sex:false
}
getPerson(obejct)

 解读:以上代码的getPerson函数接收一个类型为PersonIf的对象,PersonIf则是约束了转入对象参数的格式的接口,即obejct对象必须要有和接口一样的属性,要会报错。

值得注意的是:接口有的属性,对象必须要有;对象有的属性,接口不一定强制有;

 

interface PersonIf{
    name:string;
    age:number;
    sex:boolean
}
function getPerson(obj:PersonIf):string{
    return return obj.name+obj.age
}
var obejct={
    name:'小孩',
    age:18,
}
getPerson(obejct)

一般情况下,后端接口传过来的json数据可能会根据请求参数的不同,传到前端的数据可以字段也会不太一致,或者有些什么直接参数丢失等。这时候,我们可以把interface的约束属性变成一个可选值。使用“?”符号

此时接口有的属性,对象中不一定要有了

interface PersonIf{
    name?:string;
    age?:number;
}
function getPerson(obj:PersonIf):any{
    return obj.name
}
var obj={
    name:'小孩',
}
 console.log(getPerson(obj));

值得注意的是:可选参数的时候,有返回值,方法定义的放回类型应该是一个any,因为不知道这个name是可选的,有可能是一个underfined。

还有一个方式是:(可看对数组的约束,有讲解)

b.接口对函数进行约束

接口对函数进行约束主要是对函数的参数和返回值进行约束

格式:

interface 接口名{
    (参数名1:参数类型1,参数名2:参数类型2,...):返回值类型
}
interface PersonIf{
    (name:string,age:number):string
}
let fn:PersonIf=function(name:string,age:number):string{
    return name+age
}
console.log(fn('xiaozhi',18));

c.接口对数组(或对象)的约束

格式:

interface 接口名{
    [index:number]:数组元素类型
}

如果是数组,index的类型必须是number,如果是对象,可以是string(不常用,原因是对象的属性很多情况类型是不同的,可以使用any解决)

约束数组代码:

interface array{
    [index:number]:string
}
let arr:array=['12','34']
console.log(arr);

约束对象代码:

interface obj{
    [index:string]:any
}
let duixiang:obj={
    name:'xiaozhi',
    sex:18,
    jop:{
        p1:'老师',
        p2:'家长'
    }
}
console.log(duixiang.jop.p1,duixiang.name);

4,接口对类的拓展

和抽象类有点类似,如果把类比作一个人的话,把人共有的提取出来,封装成一个抽象类;往人身上添加东西的就是接口。

比如张三是一个人,是个人就要继承人的抽象类(不吃饭、不睡觉不呼吸就不是人了);张三这个人追求个性,所以他实现了接口(红眉毛、绿口红才有个性)。这时候王五也是个人,也需要继承人这个抽象类,但是他不追求个性,所以他不实现这个接口。

类实现接口可以这么理解!!!

interface PersonIf{
    name:string;
    age:number;
    kouhong():any;
}
class person implements PersonIf{
    name:string;
    age:number;
    constructor(name:string,age:number){
        this.name=name
        this.age=age
    }
    kouhong(){
        console.log(this.name+'今年'+this.age+'岁,所以涂口红');
    }
}
var p=new person("张三",18)
console.log(p.kouhong());

 注意:接口中的方法只能定义不能有方法体;类实现接口必须重写接口内的全部属性和方法;接口可以多实现;接口和接口可以实现继承(一般使用多实现就可以了,没必要继承)

interface PersonIf1{
    id:string
    age:number;
    kouhong():any;
}
interface PersonIf2{
    name:string;
    meimao():any;
}
class person implements PersonIf1,PersonIf2{
    id:string;
    name:string;
    age:number;
    constructor(name:string,age:number,id:string){
        this.name=name
        this.age=age
        this.id=id
    }
    kouhong(){
        console.log(this.name+'今年'+this.age+'岁,所以涂口红');
    }
    meimao(){
        console.log("眉毛"); 
    }
}
var p=new person("张三",18,'11111')
console.log(p.kouhong());

 5.注释

类可以同时继承一个类和实现多个接口

六.泛型

泛型:泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。.泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

1.函数泛型

有这么一个需求,一个函数可以返回任意类型,可以使用any,但是使用any异味这放弃了类型检查,这时候就需要泛型来解决,使其传入什么类型就放回什么类型。

泛型是一个参数化类型,可以检查参数列表的合法性。

function fn<T>(name:T):T{
    return name
}
//这种调用方式相当any
//console.log( fn('小智'));
//console.log( fn(12));
//console.log( fn(false));
console.log( fn<string>('小智'));
console.log( fn<number>(12));
console.log( fn<boolean>(false));

上面的代码中,<T>表示泛型,T表示泛型类型名称(传入什么就是什么),这里的泛型类型也可以是typescript中的某个数据类型。在这个代码中,返回的是泛型类型,我们也可以指定返回的类型(不是泛型)

function fn<Y>(name:Y):string{
    return 'CODD'
}
console.log( fn<string>('小智'));

 但是以下代码是错误的

function fn<Y>(name:Y):string{
    return name
}
console.log( fn<string>('小智'));

 因为返回的是name,而name的类型不一定是string类型,有可能是number类型。

 2.泛型类

有这么一个需求,定义一个类,该类中功能是添加数组元素。要求只能添加同一个数据类型的数据。

class AddArray<T>{
     array:T[]=[];
    add(item:T):void{
        this.array.push(item)
    }
    getArray():any{
        return this.array
    }
}
var m=new AddArray<string>()
m.add('xiozhi')
m.add('xiaolei')
m.getArray()
console.log(m.getArray());
var m2=new AddArray<number>()
m2.add(12)
m2.add(13)
console.log(m2.getArray());

 

3.泛型接口

i.泛型接口之函数泛型接口

顾名思义,就是把泛型加载接口中的函数上

interface DataInterface{
    <T>(str:T):T
}
var getData:DataInterface=function<T>(name:T):T{
    return name
}
console.log(getData("xiaozhi"));

ii.泛型接口之接口泛型接口

顾名思义,就是将泛型定义在接口上。

interface DataInterface<T>{
    (str:T):T
}
function fn<T>(name:T):T{
    return name
}
var getData:DataInterface<string>=fn
var getData1:DataInterface<number>=fn
console.log(getData("小白"));
console.log(getData1(12));

在定义的时候就直接指定泛型类型,简化写法(函数只调用一次)

interface DataInterface<T>{
    (str:T):T
}
var getData:DataInterface<string>=function<T>(name:T):T{
    return name
}
console.log(getData("小白"));

七.typescript模块化

使用了JavaScript模块化方式,使用export向外暴露模块内容,使用import引入暴露出来的数据。

新建如下文件

每个文件中写入:

user.ts

import userImp from './userImp'
class User implements userImp{
    name:string
    age:number
    constructor(name:string,age:number){
        this.name=name
        this.age=age
    }
    getName():string|undefined{
        return this.name
    }
    setName(name:string):void{
        this.name=this.name
    }
    getAge():number|undefined{
        return this.age
    }
    setAge(age:number){
        this.age=age
    }
}
export default  User

userImp.ts

interface userImp{
    name:string
    age:number
}
export default userImp

 index.ts

import User from './user'
var user= new User('XIAOHZI',18)
console.log(user.age);
console.log(user.name);

 由于模块化编程是编译成的js无法被浏览器运行,这时候需要通过node来运行jindex.js文件

 1.命名空间

在写typescript的时候,定义类或者变量多的时候,可能会导致命名冲突,这时候我们可以使用命名空间来把代码分开,格局命名冲突。

namespace 空间名{........}

在命名空间内需要通过export将需要导出的内容导出就可以了。

namespace A{
   export class a{
        name:string|undefined
        getName():any{
            console.log(this.name);
            return this.name
        }
    }
}
namespace B{
 export  class a{
        name:string|undefined
        getName():any{
            console.log(this.name);
            return this.name
        }
    }
}
var Aa=new A.a()
var Ba=new B.a

如果想要将命名空间模块化,也需要使用export将空间导出

export namespace A{
   export class a{
        name:string|undefined
        getName():any{
            console.log(this.name);
            return this.name
        }
    }
}

八.装饰器

装饰器是一个方法,可以向一个类、方法、属性、参数注入内容,用于扩展其功能。

使用方式

@装饰器名(param:any){...}

接收一个参数,这个参数表示的是当前类、方法、属性或者参数。

主要:要支持装饰器,需要在ts配置文件中打开:

"experimentalDecorators": true,

1.无参类装饰器

无参装饰器params就是类本身

function logDom(params:any){
    //param表示的是类本身
    // 向当前类添加属性
   params.protoType.age='12'
    // 向类里面添加方法
    params.protoType.getAge=function(){
        console.log("11");   
    }
}
@logDom
class Dome{
    constructor(){}
    show():void{
        console.log("累呀");
    }
}
var dome:any=new Dome()
console.log(dome.age);
dome.getAge()

2.有参装饰器:返回一个函数

有参装饰器的params表示的是传入的参数,target表示类本身。

function logDom(params:any){
    //param表示的是类本身
    // 向当前类添加属性
    console.log(params)
    return function(target:any){
        target.protoType.age='12'
        // 向类里面添加方法
        target.protoType.getAge=function(){
            console.log("11");
            
        }
    }
  
}
@logDom("你好")
class Dome{
    constructor(){}
    show():void{
        console.log("累呀");
    }
}
var dome:any=new Dome()
console.log(dome.age);
dome.getAge()

类装饰器还可以通过重载的方式修改累的构造函数和方法

function decorateDome(target:any){
    return class extends target{
        url:any='你好'
        getUrl(){
            console.log("不好的");
        }
    }
}
@decorateDome
class Dome{
    url:string|undefined;
    constructor(){
        this.url="我是一个url"
    }
    getUrl(){
        console.log(this.url);
        
    }
}
var dome=new Dome()
console.log(dome.url,);
dome.getUrl()

3.属性装饰器

属性装饰器返回的函数多出了一个,表示该属性

function decorateDome(params:any){
    return function(target:any,atrr:any){
        target[atrr]=params
    }
    
}
class Dome{
    @decorateDome("属性装饰器")
    url:string|undefined;
    constructor(){
        // this.url="我是一个url"
    }
    getUrl(){
        console.log(this.url);
        
    }
}
var dome=new Dome()
console.log(dome.url);

4.方法装饰器

方法装饰器的作用可以用来监视,修改或者替换方法的定义

方法装饰器运行的时候需要传入三个参数

对于静态成员来说是类的构造函数,对于实例成员是类的原型

成员的名字

成员的属性描述符号

function decorateDome(params:any){
    return function(target:any,methodName:any,desc:any){
      console.log(params);
      console.log(target);
      console.log(methodName);
      console.log(desc);      
    }   
}
class Dome{
    url:string|undefined;
    constructor(){
        // this.url="我是一个url"
    }
    @decorateDome("属性装饰器")
    getUrl(){
        console.log(this.url);
        
    }
}
var dome=new Dome()

 可以看到target就是类的本身,methodName是方法名,desc是对这个方法的表述,而value就是该方法本身

a,使用方法装饰器替换方法

function decorateDome(params:any){
    return function(target:any,methodName:any,desc:any){
          desc.value=function(...args:any[]){
            console.log(args);    
          }
    }   
}
class Dome{
    url:string|undefined;
    constructor(){
    }
    @decorateDome("属性装饰器")
    getUrl(){
        console.log(this.url);   
    }
}
var dome=new Dome()
dome.getUrl("你好","haha")

 

这时候我们可以看到该方法以及被替换了,但是在很多情况下,我们是需要修改这个方法,而不是替换,这时候可以使用apply实现函数的修改

function decorateDome(params:any){
    return function(target:any,methodName:any,desc:any){
          var cMethod=desc.value
          desc.value=function(...args:any[]){
            console.log(args);  
            cMethod.apply(target,args)
          }
    }   
}
class Dome{
    url:string|undefined;
    constructor(){
        // this.url="我是一个url"
    }
    @decorateDome("属性装饰器")
    getUrl(){
        console.log("我感觉还行");  
    }
}
//var dome=new Dome()
var dome:any=new Dome()
dome.getUrl("你好","haha")

 5.方法参数装饰器

作用:当函数被调用的时候,使用方法装饰器向类原型添加一些属性或者方法等。

格式:

 return function(target:any,methodName:any,paramsIndex:any){
      ...  
    }

 paramsIndex:表示该参数的索引

function decorateDome(params:any){
    return function(target:any,methodName:any,paramsIndex:any){
      console.log(paramsIndex); 
      target.apiUrl="哈哈哈"    
    }   
}
class Dome{
    url:string|undefined;
    constructor(){
        // this.url="我是一个url"
    } 
    getUrl(@decorateDome("hello") name:any){
    }
}
var dome:any=new Dome()
dome.getUrl("你好")
console.log(dome.apiUrl);

 6.装饰器的执行顺序

属性装饰器>方法装饰器>方法参数装饰器>类装饰器

如果同种装饰器有多个,执行顺序从下到上,右到左。

 

标签:function,typescript,console,name,基础,学习,any,string,log
来源: https://www.cnblogs.com/waywordcode/p/15476502.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有