ts 语法基础

115 阅读6分钟
ts 的数组定义方式两种
let list:number[]=[13,2,3]

let list:Array<number>=[1,2,4]
// 元组,可以不是同等类型的元素,但是类型必须一一对应
let x:[number,string]=[12,'ssj']
x=[10,'shdsj'] //true
x=['jsj0',10] //error
//枚举  为一组数值赋予名字来让其他的变量继承
enum color{red,green,blue}
let c:color=color.blue
let colorName:string=color[2]
console.log(colorName)
//枚举  为一组数值赋予名字来让其他的变量继承
enum color{red,green,blue}
let c:color=color.blue
let colorName:string=color[2]
// console.log(colorName)

// 任意值
let notSure:any=4;
notSure='sjsjj'
notSure=true
let list:any=[1,'sjsj',true]

// 空值
// void表示没有任何类型,任何返回值
function warning():void{
    console.log('hhh')
}

// null和undefined
// unll undefined是所有类型的子类型。可以把特们赋值给number类型
// 当你指定了--strictNullCheck,null和undefined只能赋值给void

// never表示那些永不存在的类型
// never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式后者箭头函数表达式的返回值类型
function error(message:string):never{
    throw new Error(message)
}


// 断言类型
// 如果你比ts更了解某个实体具有的类型,可以使用类型断言
// 类型断言的有两种形式
// 1.尖括号
let someValue:any='this is a string';
let strLength:number=(<string>someValue).length
// console.log(strLength)
// 2.as语法
let  strLength2:number=(someValue as string).length


# // 解构赋值
// 解构数组
let input=[1,2]
let [first,second]=input
// console.log(first,second)

// let [a=3,b=a,f=b]=[1,2]
// console.log(a,b,f) //1,2,2

// 函数解构
function f([first,second]:[number,number]){
    console.log(first,second)
}
f([1,2])

let [first1,...other]=[1,2,3,4,6]
// console.log(first1);//1
// console.log(other);//[2,3,4,6]

let [_,a,b,d]=[1,2,3,4]
// console.log(_,a,b,d) //1,2,3,4

// 对象解构
let obj={
    a:"foo",
    b:12,
    c:'bar'    
}
// let {a,b}=obj
// console.log(a,b)

let {a,...other}=obj;
let total=other.b+other.c.length
console.log(total)

// 属性重命名
let {a:newName1,b:newName2}=obj



接口

// 接口
interface LabelValue{
    label:string;
}

function printLabel(labelObj:LabelValue):void{
    console.log(labelObj.label)
}

let myLabelObj={size:10,label:'哈哈哈哈'}
printLabel(myLabelObj)

// 可选属性
// 接口中的属性不是全都必须的,有些只在某些条件存在。  使用?
interface SquareConfig{
    color?:string;
    width?:number;
}

function createSquare(config:SquareConfig):{color:string;area:number}{
    let newSquare={color:"white",area:100};
    if(config.color){
        newSquare.color=config.color;
    }
    if(config.width){
        newSquare.area=config.width
    }
    return newSquare
}
let mySquare=createSquare({color:'black'});

image.png

只读

// 只读属性----属性面前设置 readonly
interface Point{
    readonly x:number;
    readonly y:number;
}

let p1:Point={x:10,y:20}
p1.x=111  //error

函数类型接口

// 函数类型接口
// 使用接口表示函数类型的时候,我们需要给接口定义一个调用签名
// 签名需要定义返回值类型,每个参数的类型
interface SearchFunc{
    (source:string,subString:string):boolean
}

let mySearch:SearchFunc=function(source:string,subString:string){
   let result=source.search(subString)
   return result>-1     
}
mySearch('hhh','jjj')

// 参数类型可以不必与接口定义的名字匹配
let mySearch:SearchFunc=function(src:string,sub:string){
    let result=src.search(sub)
    return result>-1     
 }
 mySearch('hhh','jjj')
 
 

索引类型接口

// 可索引的类型
// 描述能够通过索引得到类型
interface StringArray{
    //还可以将索引签名设置为只读,防止给索引赋值
  readonly  [index:number]:string  //stringArray接口,具有索引签名,相当于number去索引stringArray时会得到string类型的返回值
}

let myArr:StringArray=["bbb",'aaa']
let mystr:string=myArr[0]

// 类
// 继承,dog派生类,派生自animal,继承了animal的move()
class Animal{
    move(distanceInMeters:number=0){
        console.log(`Animal moved ${distanceInMeters}m`)
    }
}
class Dog extends Animal{
    bark(){
        console.log('woof,woof')
    }
}

const dog=new Dog()
dog.bark()
dog.move(10)

=================================================================
class Amimal{
    name:String;
    constructor(theName:string){
        this.name=theName
    }
    move(distanceInMeters:number=0){
        console.log(`${this.name}移动了${distanceInMeters}米`)
    }
}

class Snake extends Amimal{
    // 构造函数里访问this的属性之前,必须要调用super()
    constructor(name:string){
        super(name)
    }
    // 重写了父类方法
    move(distanceInMeters=5) {
        console.log('爬行')
        super.move(distanceInMeters)
    }
}

class Horse extends Amimal{
    constructor(name:string){super(name)}
    move(distanceInMeters=45){
        console.log('跑跑跑')
        super.move(distanceInMeters)
    }
}

let sam=new Snake('我是蛇')
let tom:Amimal=new Horse('我是马')
sam.move()
tom.move(34)

============================================================
# 属性修饰
//pulic ,private ,protect
// ts 中,成员都默认为public
// private  --->当被private修饰 就不能在声明它的类的外部访问
// 比如
class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // 错误: 'name' 是私有的.

=============================================================
class Person{
   protected name:string;
    constructor(name:string){this.name=name}
}

class Employee extends Person{
    private deaprtment;
    constructor(name:string,department:string){
        super(name)
        this.deaprtment=department
    }
    public introduce(){
        return `大家好,我叫${this.name} 我在${this.deaprtment}工作`
    }
}



let tom=new Employee('tom','清华大学')
console.log(tom.introduce())  //那么被protected修改了不能被外部直接访问,但是我们可以通过实例的方法访问
console.log(tom.name) //erro  //被protected修饰了就不能在外部访问

protected也能修饰构造函数,但是被修饰的类不能实例化,但是可以继承

readonly修饰类的属性时,必须在类实例化的时候就进行初始化赋值,之后无法更改

getter/setter

// ts支持 getter/setter来截取对象成员的访问
let passcode='123'
class Employee{

   private _fullName:string
    constructor(name:string){
        this._fullName=name
    }
   get fullName():string{
    return this._fullName;
   }

   set fullName(newName:string){
    if(passcode&&passcode=='123'){
        this._fullName=newName
    }else{
        console.log("error")
    }
   }
}
let employee=new Employee('李白')
employee.fullName='韩信'
console.log(employee.fullName)

# 抽象类

// 抽象类
// 抽象类作为其他派生类的基类使用,一般不会被实例化
// abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法
abstract class Animal{
    abstract makeSound():void;
    move():void{
        console.log('叫')
    }
}
// 抽象类的抽象方法都只是定义方法签名而不包含方法体
//抽象子类必须重写父类的抽象方法



abstract class Department{
    constructor(public name:string){} //参数属性
    printName():void{
        console.log('部门的名字:'+this.name)
    }
    abstract printMeeting():void;//必须在派生类实现
}

class AccountingDepartment extends Department{
    constructor(){
        super('审计部门')
    }
    printMeeting(): void {
        console.log('部门会议时间定在9点')
    }
    generateReports():void{ //报错,抽象类中没定义
        console.log(`每天汇报`)
    }
}

let dp:Department;//创建抽象类的引用,抽象类无法创建实例
// dp=new Department();//erro 不允许创建抽象类的实例
dp=new AccountingDepartment();//允许对抽象子类进行实例和赋值
// dp.name="审计部门"
dp.printMeeting()
dp.printName()
// dp.generateReports()//方法在声明的抽象类中不存在

泛型

函数传入的参数类型与返回的结果同类

// 泛型
// 考虑重用性,组件不仅能支持当前的数据类型,同时支持未来的数据类型
//要求是函数传入的参数类型与返回的结果同类型!!!!!!!!!!!!!!!!
function add<T>(arg:T):T{
    return arg
}

泛型变量

// 泛型变量
// 使用泛型函数时,你必须把这些参数当作是任意或所有类型!!!!!!!!!!!!!

function identity<T>(arg:T):T{
    return arg
}
// 如果想打印出传入参数的长度
function identity<T>(arg:T):T{
    //console.log(arg.length) //直接打印会报错
    return arg
}
// 因为泛型传入的是任何类型的参数,如果传入的参数是数字类型,他没有length属性。就会报错
// 因此要这么书写
function identity<T>(arg:T[]):T[]{
    console.log(arg.length) //不会报错
    return arg
}
// 或者
function identity<T>(arg:Array<T>):Array<T>{
    console.log(arg.length) //不会报错
    return arg
}

泛型类型

// 泛型变量
// 使用泛型函数时,你必须把这些参数当作是任意或所有类型!!!!!!!!!!!!!

function identity<T>(arg:T):T{
    return arg
}
// 泛型函数类型
let myIdentity:<T>(arg:T)=>T=identity

// 也可以使用不同的泛型参数名,只要在数量上和使用方法能对应上就可以
let myIdentity:<u>(arg:U)=>U=identity

//也可以使用字面量来定义泛型函数
let myIdentity:{<T>(arg:T):T}=identity

// 把字面量拿出来作为一个接口
interface GenericIdentityFn{
    <T>(arg:T):T
}
let myIdentity:GenericIdentityFn=identity

// 把泛型参数当作整个接口的一个参数,这样就能清除的知道使用的具体是哪个泛型类型
interface GenericIdentityFn<T>{
    (arg:T):T;
}

let myIdentity:GenericIdentityFn<number>=identity

泛型类

// 泛型类
class GenericNumber<T>{
    zeroValue?:T;
    add?:(x:T,y:T)=>T
}
let myGenericNumber=new GenericNumber<number>();
myGenericNumber.zeroValue=0;
myGenericNumber.add=function(x,y){return x+y}

let stringNumeric=new GenericNumber<string>()
stringNumeric.zeroValue='哈哈哈'
stringNumeric.add=function(x,y){return x+y};

console.log(stringNumeric.add(stringNumeric.zeroValue,'test'))


// 泛型约束

// 文章上篇中初始使用泛型时遇到过无法给参数设置length的情况
// 因此还可以使用泛型约束的方式,限制函数去处理任意带有.length属性的所有类型
//只要传入的类型有这个属性,我们就运行,就是说至少包含这一属性
interface lengthwise{
    length:number
}
function logginIndentify<T extends lengthwise>(arg:T):T{
    console.log(arg.length)
    return arg;
}