首页 > 其他分享 >typescript学习文档(二)

typescript学习文档(二)

时间:2024-04-08 15:58:05浏览次数:12  
标签:typescript console string number 学习 文档 let 报错 log

1、安装typescript

全局安装:npm install -g typescript
检查是否安装成功(出现版本号表示安装成功):tsc -v
如果使用tsc指令出现如下错误:
image.png
解决办法:

  1. 以管理员的身份运行vscode
  2. 终端执行:get-ExecutionPolicy,结果:Restricted
  3. 终端执行:set-ExecutionPolicy RemoteSigned
  4. 终端执行:get-ExecutionPolicy,结果:RemoteSigned

image.png

2、编写第一个typescript程序

  1. 创建ts文件:hello_world.ts
  2. 编写代码:
(() => {
    function sayHi(str:String){
        return '你好:'+str
    }
    //sayHi(123) 报错: 类型错误
    sayHi('bob')
    let num:Number = 123
    console.log(num)
})()
  1. 编译ts代码:

**注意:**浏览器无法识别ts代码,故需要把ts代码编译成js代码后才能被浏览器解析使用,即 **ts --> js --> 执行**

  1. 手动编译:**tsc ./hello_world.ts**
  2. vscode自动编译:

image.png
编译ts后,会生成一个对应的js文件:
image.pngimage.png

3、基本数据类型声明

基本数据类型:number、string、boolean、undefined、null、symbol、bigint

//基本数据类型声明
//注意:声明类型时,既可以用大写又可以使用它小写,如number、Number都可以
//ts编译器有自动检测类型机制,即声明变量但没有声明类型时,ts编译器会根据语法自动检测该变量的类型,故后续为改变量赋值为其他类型时会报错
//数字类型:number
let num:number = 123
//num = 'abc'//报错
num = 456
console.log(num)

//字符串类型:string
let str:string = 'you'
let str1 = 'me'
// str = 123 报错
str = 'he'
//str1 = 123 报错   自动检测类型机制
console.log(str,str1)

// 布尔类型:boolean
let flag:boolean = true
// flag = 'true' 报错
flag = false
console.log(flag)

// undefined和null:不常用
let u:undefined = undefined
let n:null = null
// u = 123 报错
// n = {} 报错
console.log(u,n)

4、引用数据类型声明(object、array)

// 引用数据类型声明
//数组:Array
//第一种方法:
let arr1:[] = [] //定义空数组,没有指定元素类型
// arr1 = [1,2,3] 报错
// arr1 = ['a','v'] 报错
arr1 = []

let arr2:number[] = [] //指定数组中的元素必须是number类型
// arr2 = ['a','v'] //报错
arr2 = []
arr2 = [1,2,3] 

//第二种方法:泛型<T>
let arr3:Array<number> = [] //声明数组,并指定元素的类型为number类型
// arr3 = ['a','v'] 报错
arr3 = []
arr3 = [1,2,3]

let arr4:Array<string> = ['a','b'] //声明数组,并指定元素的类型为string类型
arr4 = []
arr4 = ['this','is','a','apple']

//Object: 表示非原始类型,除了number、string、boolean之外的类型
let obj:object = {}
// obj = 123 报错
// obj = 'abc' 报错
// obj = true 报错
// obj = null 报错 与版本有关,有的版本不会报错,以及在严格模式下也会报错
// obj = undefined 报错 与版本有关,有的版本不会报错,以及在严格模式下也会报错
obj = [] //不会报错,数组也属于对象,typeof [] === 'object' ----> true
obj = new String() //不会报错,得到的是一个实例化“对象”
obj = String //不会报错,是一个类

5、声明any和void类型

//any和void类型声明:
//any:表示任何类型
let test:any = 123
test = 'abc'
test = true
test = false
test = {}
test = []

let newArr:any[] = [100,1,3,'this',false,true]
// console.log(newArr[0].split('')) 
//报错:newArr[0].split is not a function  
//原因:newArr[0]是100,这是一个数字类型,数字类型没有split方法
// any的优点:在我们不知道返回值类型的时候,使用any声明类型,就能避免报错
// any的缺点:在我们需要操作变量时,由于无法确定值类型,所以可能出现错误的情况

//void:表示没有类型,一般用于声明函数没有返回值,声明变量没有意义
//声明函数:
function demo():void{
    console.log(123)
}
console.log(demo()) //undefined

//声明变量:
let u1:void = undefined
// let u2:void = null 报错
// let u3:void = 12 报错

6、类型推论

类型推论:如果没有明确的指定类型,那么 TypeScript 会依照类型推论(Type Inference)的规则推断出一个类型

let test1 = 123 //ts会依照类型推论的规则推断出test1是一个number类型
// test1 = 'abc' 报错

let test2  //ts会依照类型推论的规则推断出test2是一个any类型
test2 = 123
test2 = 'this'
test2 = false

7、联合类型

**联合类型:**表示取值可以为多种类型中的一种
注意:

  • 联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型
  • 只能访问此联合类型的所有类型里共有的属性或方法
let test3: number | boolean = true //变量test3的值只能是number或者boolean
test3 = 1 
test3 = false
// test3 = 'test' 报错

let test4:number | boolean | string = false
test4 = 123
// console.log(test4.split('')) 报错,原因:当前的变量test4是一个number类型,没有split方法
test4 = 'this is a apple'
console.log(test4.split(''))
test4 = false
// console.log(test4.split('')) 报错,原因:当前的变量test4是一个boolean类型,没有split方法
console.log(test4.toString()) //toString(),是number、string、boolean类型共有的方法

8、接口

对象类型

**接口:**可以理解为是一种约束,它是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。
注意:

  1. 接口一般首字母大写,有的编程语言中会建议接口的名称加上 I 前缀
  2. 定义的变量比接口少一些属性和多一些属性都是不允许的(赋值的时候,变量的形状必须和接口的形状保持一致)
interface IPerson {
    name:string;
    age:number;
    height:string;
}

let tom:IPerson = {
    name:'Tom',
    age:18,
    height:'180cm',
    // sex:'男'报错
}

可选属性:

通过 ? 来定义,可选属性可以被定义也可以不被定义

interface IStudent {
    name:string;
    age:number;
    sex?:string; //表示sex是一个可选属性
}
let bob:IStudent = {
    name:'bob',
    age:23,
    sex:'男',
    // width:'100cm' 报错,不可以添加属性
}
let john:IStudent = {
    name:'john',
    age:20
}

任意属性:

注意:

  1. 一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
  2. 一个接口中只能定义一个任意属性
interface IPeople {
    name:string;
    count?:number;
    [propName:string]:any; //定义任意类型
}
let one:IPeople = {
    name:'团体',
    address:'china',
    phone:'10086'
}
console.log(one)
//注意:
//一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集
//一个接口中只能定义一个任意属性
interface Person {
    name: string;
    age: number;
    [propName: string]: string | number;
}

let wick: Person = {
    name: 'wick',
    age: 25,
    gender: 'male',
};

可读属性:

使用readonly定义
**注意:**只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

interface IPerson1 {
    readonly id:number;
    name:string;
}
let wenston:IPerson1 = {
    id:10,
    name:'wenston'
}
// wenston.id = 1235 报错,只读属性不允许更改

数组类型

interface INewArray {
    [index:number]:number
}
let newArr1:INewArray = [1,2,3]
// let newArr2:INewArray = [1,2,'abc'] 报错

函数类型

interface ISearchFun {
//  (变量名:类型,...):返回值类型
    (a:string,b:string):boolean
}
const fun1:ISearchFun = function(a:string,b:string):boolean{
    return a.search(b) !== -1
}

9、函数定义

函数声明:

function sum(a:number,b:number):number{
    return a + b
}

函数表达式:

let sum1 = function(a:number,b:number):number{
    return a+b
}

函数完整写法:

let sum2:(a:number,b:number)=>number = function(a:number,b:number):number{
    return a+b
}

可选参数:

通过 ?定义
**注意:**可选参数不能放在必选参数之前,如:y不能放在x之前

let outStr = function(x:string,y?:string):string{
    return x + y
}
console.log(outStr('你好'))
console.log(outStr('你好','龙傲天'))
// 报错:变量z会报错,原因:可选参数不能放在必选参数之前
// let outStr1 = function(x:string,y?:string,z:string):string{ 
//     return x + y
// }

默认参数:

**注意:**默认参数可以放在可选和必选参数之后

let outStr2 = function(x:string,y?:string,z:string = '张三'):string{
    return x + y + z
}
console.log(outStr2('你好'))
let outStr3 = function(x:string,z:string = '李四',y?:string):string{
    return x + y + z
}
console.log(outStr3('你好'))

剩余参数:

通过 …rest 实现

let outInfo = function(a:string,b:string,...args:string[]){
    console.log(a,b,args)
}
// outInfo('a','b',1,2,3,4)//报错
outInfo('a','b','this','is','my','wife')

函数重载:

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理

//实现一个需求:当参数x、y都是数字类型时进行相加,当x、y都是字符串类型时进行字符串拼接
//函数实现:
//然而这样有一个缺点,就是不能够精确的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该为字符串
function concatFun1(x:string | number,y:string | number):string | number{
    if(typeof x === 'string' && typeof y === 'string'){
        return x + y //字符串拼接
    }else if(typeof x === 'number' && typeof y === 'number'){
        return x + y //求和
    }else{
        return '情况不存在'
    }
}
//将鼠标放在下面两个函数调用上,代码提示不够准确,代码提示:
//function concatFun1(x:string | number,y:string | number):string | number
console.log(concatFun1(1,2))
console.log(concatFun1('this','is'))
//函数重载实现:
function concatFun2(x:string,y:string):string;
function concatFun2(x:number,y:number):number;
function concatFun2(x:string | number,y:string | number):string | number{
    if(typeof x === 'string' && typeof y === 'string'){
        return x + y //字符串拼接
    }else if(typeof x === 'number' && typeof y === 'number'){
        return x + y //求和
    }else{
        return '情况不存在'
    }
}
//在编辑器的代码提示中,可以正确的看到前两个提示
console.log(concatFun2(1,2)) // 代码提示:function concatFun2(x:number,y:number):number
console.log(concatFun2('this','is'))// 代码提示:function concatFun2(x:string,y:string):string

10、类型断言

**定义:**手动指定一个值的类型
语法:

  1. 值 as 类型
  2. <类型>值

**注意:**类型断言并不是将函数强制转换为对应的类型

// function getLength(x:string | number):number{
//     if(x.length){ //报错,因为length属性只有string类型值才拥有,但变量x不能确定是string还是number
//         return x.length //报错,同上
//     }else{
//         return x.toString().length
//     }
// }
//使用类型断言解决:
function getLength(x:string | number):number{
    if((x as string).length){
        console.log('1')
        return (<string>x).length
    }else{
        console.log('2')
        return x.toString().length
    }
}
console.log(getLength('123'))
console.log(getLength(123))

注意:

  1. 将任何一个类型断言为 any,any类型是可以访问任何属性和方法的
  2. 它极有可能掩盖了真正的类型错误,所以如果不是非常确定,就不要使用 as any
  3. 一方面不能滥用 as any,另一方面也不要完全否定它的作用,我们需要在类型的严格性和开发的便利性之间掌握平衡

将任何一个类型断言为any:

// window.a = 10 报错,我们需要在window上添加一个a属性,但typescript提示window中没有a属性
//将window断言为any类型,any类型可以访问任何属性和方法
(window as any).a = 10

将any断言为一个具体类型:

//将any 断言为一个具体类型
function sumTestFun(x:any,y:any):any{
    return x + y
}
//传递的参数都为数值类型,所以可以断言返回的值是数值类型
let a12 = sumTestFun(1,2) as number // a --> 数值类型
//传递的参数都为字符串类型,所以可以断言返回的值是字符串类型
let b12 = sumTestFun('1','2') as string // b --> 字符串类型

11、类型别名

使用 type 定义,一般用于定义联合类型

type s = string //s 代表了 string
//如下:a和b都是string类型
let a:string = 'this'
let b:s = 'is'

type snb = string | number | boolean
//test和test1 都是 string、number、boolean中的一种类型
let test: string | number | boolean = 'this is'
let test1:snb = 'my wife'

12、字符串字面量类型

使用 type 定义,约束取值只能是某几个字符串中的一个

type name = '张三' | '张伟' | '张益达'
let babyName:name = '张伟' //只能取 name中的其中一个
// let babyName1:name = '张根硕'  报错

13、元组(Tuple)

数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象

let arr:number[] = [1,2,3,4] //这里指定了数组中的元素只能是number类型
//如果想数组中的元素可以有多种类型,可以使用元组定义:
//通过元组指定了第一个元素的类型为number,第二个元素的类型为string,必须保持一致
let Tarr:[number,string] = [123,'true']
//添加元素的时候,需要是元组中指定的类型,如上便是number或string类型
Tarr.push('456')
Tarr.push(456)
// Tarr.push(true) 报错,原因:添加的元素是boolean类型

//可以只赋值其中一项
let Ttom:[string,number];
// Ttom[0] = 123  报错
Ttom[0] = 'abc' 

//当直接对元组类型的变量进行初始化或赋值时,需要提供所有元组类型中指定的项
let Twick:[string,number]
// Twick = ['123'] 报错
Twick = ['123',123]

14、枚举(Enum)

  1. 枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等
  2. 枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射(枚举名和枚举值作为键值对,可以相互获取)即:枚举[枚举名] — 枚举[枚举值]
  3. 未手动赋值的枚举项会接着上一个枚举项递增

普通枚举:

enum Days {
    one,
    two,
    three
}
console.log(Days.one)
console.log(Days)//{ '0': 'one', '1': 'two', '2': 'three', one: 0, two: 1, three: 2 }

手动赋值:

enum Days1 {
    one = 7,
    two,
    three,
    four
}
//由下面的代码可得:未手动赋值的枚举项会接着上一个枚举项递增
console.log(Days1.one)// 7
console.log(Days1.two)// 8
console.log(Days1.three)// 9

//如果出现相同枚举值,后面的枚举值会覆盖前面的枚举值
enum Days2 {
    one,
    two,
    three,
    four=1,
}
console.log(Days2)//{'0': 'one','1': 'four','2': 'three',one: 0,two: 1,three: 2,four: 1}

常数项和计算所得项:

//其中red为常数项,blue为计算所得项
enum color {
    red,
    blue='blue'.length,
}
//如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错,如下:
enum color1{
    red,
    blue='blue'.length,
    // green, 报错
    green=1
}

常数枚举:

使用const enum定义
常数枚举与普通枚举的区别: 常数枚举会在编译阶段被删除,并且不能包含计算成员

const enum Direction{
    up,
    down=9,
    left,
    right,
    // to='to'.length 报错
}
console.log(Direction.up) // 0 /* Direction.up */
console.log(Direction.down)// 9 /* Direction.down */
console.log(Direction.left)// 10 /* Direction.left */

外部枚举:

使用 declare enum 定义,常用于声明文件中
外部枚举与普通枚举的区别: 外部枚举会用于编译时的检查,编译结果中会被删除,并且不能包含计算成员

declare enum Direction1{
    up,
    down,
    left,
    right=9,
    // to='to'.length 报错
}
// console.log(Direction1.up)
// console.log(Direction1.right)


//同时使用 declare 和 const 也是可以的:
declare const enum Direction2{
    up,
    down,
    left,
    right
}
console.log(Direction2.down)// 1 /* Direction2.down */
console.log(Direction2.right)// 3 /* Direction2.right */

15、类

属性和方法的定义:

class Person{
    name:string
    age:number
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
    sayHi(str:string):void{
        console.log('hi ',str)
    }
}
let p = new Person('张三',18) //new会执行constructor构造函数
p.sayHi('李四')

类的继承:

  1. 通过extends实现继承功能
  2. 子类中通过super()调用父类的构造函数constructor
  3. 子类中可以使用父类的属性和方法,通过super调用父类的方法,this调用父类的属性
  4. 字类可以重写父类的方法
//父类:
class Animal {
    name:string
    age:number
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
    outInfo(){
        console.log('我是一只动物')
    }
    sayHi(str:string){
        console.log('Hi',str)
    }
}
//子类:
class Dog extends Animal{
    color:string
    constructor(name:string,age:number,color:string){
        //通过super调用父类Animal的构造函数
        super(name,age)
        this.color = color
    }
    //重写父类Animal的sayHi方法
    sayHi(str:string):void{
        //通过super调用父类Animal的方法
        super.outInfo()
        console.log(`${str},我的名字是${this.name},我已经${this.age}岁了,我的颜色是${this.color}`)
    }
}
let dog = new Dog('拉布拉多',3,'白色')
dog.sayHi('大家好')

类的存取器:

class Name{
    firstName:string
    lastName:string
    constructor(firstName:string,lastName:string){
        this.firstName = firstName
        this.lastName = lastName
    }
    //设置存取器:
    //读取器
    get fullName(){
        return this.firstName + ' - ' + this.lastName
    }
    //设置器
    set fullName(value){
        let names = value.split('-')
        this.firstName = names[0]
        this.lastName = names[1]
    }
}
let zs = new Name('张','三')
console.log(zs.fullName)
zs.fullName = 'john-wick'
console.log(zs.fullName)

类的静态成员:

  1. 通过static定义
  2. 静态属性和方法只属于类自己,即可以通过类调用,不能通过实例化对象调用
  3. 在类中,不能使用this调用静态属性和方法
class Cat{
    static color:string = '红色'
    constructor(){
        // this.color = '白色' //color是静态属性,不能通过this操作
    }
    sayHi(str:string){
        console.log(str)
    }
    static outInfo(str:string):string{
        return `我是一只猫,${str}`
    }
}
let cat = new Cat()
console.log(Cat.color) //红色
// console.log(cat.color) //报错,实例化对象cat上不存在color属性
console.log(Cat.outInfo('yes'))
cat.sayHi('你好')
// cat.outInfo('yes')//报错,实例化对象cat上不存在outInfo方法

类的访问修饰符:

  1. public:修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
  2. private:修饰的属性或方法是私有的,不能在声明它的类的外部访问,包括子类中也不可以被访问
  3. protected:修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中是允许被访问的

总结:

  1. public:没有限制,在任何地方都可以被访问到
  2. private:只能在当前类中访问,其他任何地方都不能被访问到
  3. protected:只能在当前类和子类中访问,其他任何地方都不能被访问到
class Man{
    public name:string
    private age:number
    protected gender:string
    constructor(name:string,age:number,gender:string){
        this.name = name
        this.age = age
        this.gender = gender
    }
    public sayName(){
        console.log('my name is '+this.name)
    }
    private sayAge(){
        console.log('my age is '+this.age)
    }
    protected sayGender(){
        console.log('my gender is '+this.gender)
    }
}
class M extends Man{
    constructor(){
        super('张三',18,'男')
    }
    outInfo(){
        console.log(`姓名:${this.name}`)
        // console.log(`年龄:${this.age}`)//报错,age是私有属性(private),只能在Man类中使用
        console.log(`性别:${this.gender}`)// gender是保护属性(protected),只能在Man类和其子类M中使用
        super.sayName()
        // super.sayAge() 报错
        super.sayGender()
    }
}
let man = new Man('李四',23,'男')
console.log(man.name)
// console.log(man.age)//不能访问
// console.log(man.gender)//不能访问

let m = new M()
console.log(m.name)
m.outInfo() 
m.sayName()

参数属性:

修饰符(public、private、protected)和readonly可以用在构造函数参数中
作用:等同于在类中定义该属性,同时为该属性赋值,使代码更简单
readonly:关键字,表示只读,只允许出现在属性声明或索引签名或构造函数中
注意:

  1. 只读属性只能在构造函数中修改
  2. readonly和其他修饰符同时使用时,readonly需要放在后面,如:public readonly
class Test{
    readonly name:string
    constructor(name:string){
        this.name = name
    }
}
let t = new Test('李四')
console.log(t.name)


class Test1{
    //readonly age:number  会在类中创建一个age:number属性,并且会在构造函数中为age赋值,即:this.age = age
    constructor(readonly age:number){
    }
    //等同于:
    // readonly age:number
    // constructor(age:number){
    //     this.age = age
    // }
}
let t1 = new Test1(18)
console.log(t1.age)


class Test2{
    constructor(public age:number){


    }
}
let t2 = new Test2(233)
console.log(t2.age)


class Test3{
    constructor(private age:number){


    }
    //等同于:
    // private age:number
    // constructor(age:number){
    //     this.age = age
    // }
}
let t3 = new Test3(54)
// console.log(t3.age) 报错,无法访问age,因为这里的age是一个私有属性

抽象类:

  1. 使用 abstract 定义抽象类和其中的方法、属性
  2. 抽象类是不允许被实例化
  3. 抽象类中的抽象属性和抽象方法,在子类中必须被实现
  4. 抽象类中抽象属性不能被初始化值,也不能在构造函数中被访问
  5. 抽象类中的抽象方法只能定义,但不能被实现
abstract class Test4{
    abstract color:string 
    // constructor(color:string){
    //     //不能在构造函数中访问类的抽象属性
    //     // this.color = color 报错
    // }
    abstract sayHi()//抽象类中的抽象方法不能被实现,只能被子类实现
}


class Test5 extends Test4{
    color:string
    age:number
    constructor(color:string,age:number){
        super()
        this.color = color
        this.age = age
    }
    sayHi() {
        console.log('hi')
    }
    outInfo(){
        console.log('输出一些信息')
    }
}
let test5 = new Test5('白色',18)
console.log(test5.color)
console.log(test5.color)
test5.sayHi()
test5.outInfo()

类的类型:

与接口类似

class Car{
    color:string
    constructor(color:string){
        this.color = color
    }
}
class Bmw extends Car{
    constructor(color:string){
        super(color)
    }
}
//因为Bmw继承于Car,所以可以使用Car指定bmw的类型,因为Bmw没有在自身类中添加其他属性和方法,
//故Bmw与Car是保持一致的,所以可以使用Bmw指定car_1的类型
let car_1:Bmw = new Car('白色')
let bmw:Car = new Bmw('黑色')


class Benz extends Car{
    name:string
    constructor(color:string,name:string){
        super(color)
        this.name = name
    }
}
//因为Benz是继承于Car,所以可以使用Car指定benz的类型,因为Benz自身上有一些其他属性和方法,
//故Benz和Car并不完全一致,所以不能使用Benz指定car_2的类型
let benz:Car = new Benz('红色','C300L')
// let car_2:Benz = new Car('绿色') 报错

16、类与接口

有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces)
用 implements 关键字来实现

接口定义与实现:

interface ISing{
    name:string
    sing()
}
interface IDance{
    dance()
}
interface IRap{
    rap()
}
interface IBaseketball{
    playBaseketball()
}
//一个类实现了一个或多个接口,那么所有接口中的函数和属性都需要被实现,否则会报错
//接口定义中,只需要定义,不需要实现
class Ji implements ISing,IDance,IRap,IBaseketball{
    name: string;
    constructor(name:string){
        this.name = name
    }
    sing() {
        console.log('唱')
    }
    dance() {
        console.log('跳')
    }
    rap() {
        console.log('rap')
    }
    playBaseketball() {
        console.log('篮球')
    }
    sayName(){
        console.log('练习时长两年半的偶像练习生')
    }
}


class Cxk implements ISing,IDance,IRap,IBaseketball{
    name: string;
    constructor(name:string){
        this.name = name
    }
    sing() {
        console.log('唱')
    }
    dance() {
        console.log('跳')
    }
    rap() {
        console.log('rap')
    }
    playBaseketball() {
        console.log('篮球')
    }
    sayName(){
        console.log('蔡徐坤')
    }
}

接口继承接口:

  1. 接口之间可以继承,而且可以多继承
  2. 可以避免类需要实现多个接口,如果使用一个接口继承其他的多个接口,那么类只需要继承这一个接口便可以了,效果与类中实现多个接口一致
interface IColor{
    outColor(name:string)
}
interface IHeight{
    outHeight()
}
interface IWidth extends IColor,IHeight{
    outWidth()
}
class Monkey implements IWidth{
    height:string
    width:string
    constructor(height:string,width:string){
        this.height = height
        this.width = width
    }
    outColor(name:string):string {
        return name
    }
    outHeight() {
        return this.height
    }
    outWidth() {
        return this.width
    }
}
let monkey = new Monkey('170cm','23cm')
console.log(monkey.outColor('黄色'))
console.log(monkey.outHeight())
console.log(monkey.outWidth())

接口继承类:

  1. 接口只能继承类的属性和方法(实例属性和实例方法)
  2. 构造函数、静态属性、静态方法都是不会继承的
class NewPerson {
    name:string
    constructor(name:string){
        this.name = name
    }
    sayHi(){
        console.log('hi')
    }
}

interface IPersonTest extends NewPerson{
    address:string
    run()
}

let person:IPersonTest = {
    name:'张三',
    address:'中国',
    sayHi(){
        console.log('hello')
    },
    run() {
        console.log('跑步')
    },
}

17、声明合并

如果定义了两个相同名字的函数、接口或类,那么它们会合并成一个类型

函数合并:

可以使用函数重载定义多个函数类型

function concatFun2(x:string,y:string):string;
function concatFun2(x:number,y:number):number;
function concatFun2(x:string | number,y:string | number):string | number{
    if(typeof x === 'string' && typeof y === 'string'){
        return x + y //字符串拼接
    }else if(typeof x === 'number' && typeof y === 'number'){
        return x + y //求和
    }else{
        return '情况不存在'
    }
}
//在编辑器的代码提示中,可以正确的看到前两个提示
console.log(concatFun2(1,2)) // 代码提示:function concatFun2(x:number,y:number):number
console.log(concatFun2('this','is'))// 代码提示:function concatFun2(x:string,y:string):string

接口合并:

interface IA{
    price:number
}
interface IA{
    count:number
}
//等同于:
// interface IA{
//     price:number
//     count:number
// }
let aTest:IA = {
    price:100,
    count:99
}


interface IB{
    price:number,
}
interface IB{
    // price:string 接口合并时,合并的属性的类型必须是相同的,所以这里的price应该是number类型
    price:number
    count:number
}
let bTest:IB = {
    price:12,
    count:12
}


interface IC{
    name:'小白'
    age:number
}
interface IC{
    // name:'小红' 接口合并时,合并的属性的类型和字面量(值)必须是相同的,所以这里的name应该是’小白‘,而不是’小红‘
    name:'小白'
    age:number
}
let cTest:IC = {
    name:'小白',
    age:18
}


interface ID{
    width:string
    getColor(color:string)
}
interface ID{
    height:string
    getColor(color:string,temp:number)
}
//等同于:
interface ID{
    height:string
    width:string
    getColor(color:string)
    getColor(color:string,temp:number)
}

类合并:

类的合并与接口的合并规则一致

18、泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

function createArr(length:number,value:any):any[]{
    let result = []
    for(let i=0;i<length;i++){
        result[i] = value
    }
    return result
}
console.log(createArr(10,'this'))
//上面这段代码进行编译不会报错,但是有一个缺陷,
//返回值是一个数组,但是里面元素的类型可以是任意类型,
//预期是返回数组中的元素类型与value类型一致
//使用泛型实现:
//T : 表示任意类型;如下代码可见,返回数组中的元素类型与value的类型始终保持一致
function createNewArr<T>(length:number,value:T):Array<T>{
    let result = []
    for(let i = 0;i< length;i++){
        result[i] = value
    }
    return result
}
//调用时可以指定它的具体类型为string或其他,也可以不手动指定,而让类型推论自动推算出来
console.log(createNewArr<string>(10,'this'))//value和返回的数组元素的类型都为string
console.log(createNewArr(5,0))//value和返回的数组元素的类型都为number(类型推论)

多个类型参数:

定义泛型时,可以定义多个类型参数

function swap<T,U>(tuple:[T,U]):[U,T]{
    return [tuple[1],tuple[0]]
}
console.log(swap([true,'this']))

泛型约束:

//在函数内部使用泛型变量时,由于事先不知道泛型的具体类型,不能随意操作它的属性和方法
function outVal<T>(arg:T):T{
    // console.log(arg.length) 报错,不知道泛型的具体类型,所以无法确定arg是否具有length属性
    return arg
}
//使用泛型约束,只允许这个函数传入那些包含length属性的变量:
interface ILengthWise{
    length:number
}
//由于 T 继承了 ILengthWise接口 ,所以传递的参数arg中必须包含(实现)接口中的length属性,
//如果没有,在编译阶段便会报错
function outNewVal<T extends ILengthWise>(arg:T):T{
    console.log(arg.length)
    return arg
}
console.log(outNewVal('this is'))
//多个类型参数之间也可以相互约束
//这样U中就不会出现T中不存在的字段
function copyFields<T extends U, U>(target: T, source: U): T {
    for (let id in source) {
        target[id] = (<T>source)[id];
    }
    return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 };
copyFields(x, { b: 10, d: 20 });
// copyFields(x, { b: 5, d: 9, e:8}); //报错,第二个参数中的属性,必须在x中存在

泛型接口:

使用一个包含泛型的接口,来定义函数的形状

interface ICreateArr{
    <T>(length:number,value:T):Array<T>
}
let newCreateArr:ICreateArr = function <T>(length:number,value:T):Array<T>{
    let result:T[] = []
    for(let i=0;i<length;i++){
        result[i] = value
    }
    return result
}
console.log(newCreateArr(5,true))
console.log(newCreateArr<boolean>(5,false))
//将泛型参数提前到接口名上:
//注意:如将泛型参数放到接口名后定义,那么在使用接口的时候就需要定义泛型的类型
interface ICreateNewArr<T>{
    (length:number,value:T):Array<T>
}
let newCreateNewArr:ICreateNewArr<string> = function <T>(length:number,value:T):T[]{
    let result:T[] = []
    for(let i=0;i<length;i++){
        result[i] = value
    }
    return result
}
//报错,因为在使用接口ICreateNewArr时,已经定义了泛型的类型为string,
//所以这里只能传递string类型的参数
// console.log(newCreateNewArr(5,false)) 
console.log(newCreateNewArr(5,'are'))

泛型类:

与泛型接口类似

class CreatTest<T>{
    value:T
    add:(x:T,y:T) => T
}
let ct = new CreatTest<number>()
// ct.value = 'this' 报错,'this'是string类型,而value需要的是number类型
ct.value = 1
//报错,x、y需要的是number类型,返回值的类型也应该是number类型
// ct.add = function(x:string,y:string){ return x + y }
//报错,返回值需要与 T 保持一致,即返回值需要时number
// ct.add = function(x:number,y:number){return ''}
ct.add = function(x:number,y:number){return x+y}

泛型参数的默认类型:

当使用泛型时没有在代码中直接指定类型参数,从实际值参数中也无法推测出时,这个默认类型就会起作用

function createArray<T = string>(length:number,value:T):T[]{
    let result:T[] = []
    for(let i=0;i<length;i++){
        result[i] = value
    }
    return result
}

标签:typescript,console,string,number,学习,文档,let,报错,log
From: https://blog.csdn.net/weixin_44066182/article/details/137512519

相关文章

  • Python学习笔记-001
    记录一下重学python,虽然python老早就接触了,更多的还是停留在语法层面,老c++了。最近打算从头开始系统拉一下python的基础,先预计8天学完。后面还打算系统学一下Numpy,Pandas和Matplotlib。python基础教程python简介检查是否安装python,终端输入python--versionpython是一种解释......
  • Java面象对象编程学习(保姆级教学)
    1、基本数据类型和引用数据类型的区别(用内存的角度):基本数据类型:数据值是存储在自己的空间中特点:赋的值也是真实的值引用数据类型:数据值存储在其他空间中,自己空间存储的是地址值特点:赋的值是地址值★【注意:在静态代码块中,随着类的加载进行,而且只进行一......
  • MySQL学习路线一条龙
    引言在当前的IT行业,无论是校园招聘还是社会招聘,MySQL的重要性不言而喻。面试过程中,MySQL相关的问题经常出现,这不仅因为它是最流行的关系型数据库之一,而且在日常的软件开发中,MySQL的应用广泛,尤其是对于Java后端开发者来说,熟练掌握MySQL已成为他们技术能力评估的重要指标。因此,My......
  • 模拟CMOS集成电路学习笔记:单级放大器(1)
            放大器顾名思义是将信号进行放大,在简单电路中我们经常默认为放大是一种线性行为,即y=kx+t。在模拟集成电路中,一个放大器需要考虑的东西有很多比如功耗、线性度、最大电压摆幅、增益等等。        如图即为拉扎维先生所提到的模拟电路设计八边形法则,这......
  • 【学习】软件测试中为什么要进行接口测试?
    接口测试是软件开发过程中不可或缺的一环,它主要是对软件系统中各个模块之间的接口进行测试,以验证它们是否能够正确地交互和协作。接口测试的目的是确保软件系统的各个部分能够无缝地协同工作,从而提高整个系统的质量和稳定性。一、什么是接口测试接口测试是指对软件系统中各......
  • Lumos学习王佩丰Excel第二讲:单元格格式设置
    今天学会GIF录制了,分享知识会更简便一些,话不多说,开始吧~一、美化表格1、设置单元格格式的路径从菜单栏进入:选中区域(单元格)-右键“设置单元格格式”:2、合并单元格合并一行批量合并多行,选择跨越合并3、对齐方式对齐方式这边应该很好理解吧,就是文字在单元格中的具......
  • Lumos学习王佩丰Excel第一讲:认识Excel
    最近发现自己在操作excel的一些特殊功能时会有些不顺手,所以索性找了一个比较全的教程(王佩丰excel24讲)拿来学习,刚好形成文档笔记,分享给有需要但没有时间看视频的朋友们。整体笔记以王老师授课的知识点去记录,加入一些自己的理解和由于版本问题(我使用的是MicrosoftOffice家庭和......
  • 微服务学习-Docker安装
    0.安装DockerDocker分为CE和EE两大版本。CE即社区版(免费,支持周期7个月),EE即企业版,强调安全,付费使用,支持周期24个月。DockerCE分为stabletest和nightly三个更新频道。官方网站上有各种环境下的安装指南,这里主要介绍DockerCE在CentOS上的安装。1.Ce......
  • 微服务学习-Ribbon,Nacos
    Ribbon负载均衡在Eureka的学习中,通过添加注解@LoadBalance进行负载均衡,实现的原理是什么?请求端发送信息,LoadBalancerInterceptor负载均衡拦截器拦截请求,根据servername去注册中心获取请求地址,使用负载均衡选择调用哪一个。负载均衡的策略设置1.代码方式:在请求的启动类中......
  • 【学习笔记】数论分块
    先看一个例子:给出正整数\(n(n\leq10^{12})\),计算:\[\sum_{i=1}^n\lfloor\frac{n}{i}\rfloor\]如果直接暴力,复杂度为\(O(n)\),无法在1s内通过,但使用数论分块(整除分块)可以将复杂度降至\(O(\sqrt{n})\)。先看个例子,当\(n=100\)时,\(i\)和\(\lfloor\frac{n}{i}\r......