ts-基础总结

ts 笔记

1. ts 基础类型

冒号后面叫做 类型注解

// 使用ts声明一个字符串类型的变量
let name:string = 'zrs'

// 使用ts声明一个数字类型的变量
let age:number=18

// 使用ts声明一个布尔类型的变量
let flag:boolean=false
// 声明 nul 类型的变量 只能赋值为 null
let aaa:null=null

// 声明 undefined 类型的变量,只能声明为 undefined
let bbb:undefined=undefined

2. ts数组

// 声明一个只能装 数字类型的数组
let arr1:number[]=[]

// 声明一个只能装 字符串类型的数组
let arr2:string[]=[]

// 使用泛型声明一个数组 该数组只能装 数字类型的元素
let arr3:Array<number>=[] 

// 使用泛型声明一个数组 该数组只能装 字符串类型的元素
let arr4:Array<string>=[]

3. any 类型

// 声明一个 any 类型的变量,那么这个变量可以赋任何类型的值
let a:any;

a=123

a='asd'

a=true
// 以上代码都不会报错

// 因为 any 类型可以赋值给 任何类型,所以下面的代码不报错
let e:number=a



// 在ts中 声明变量的时候,不注解,不赋值,那么 就是隐式的任意类型
let b;

b=100

b='sdf'
// 以上代码 不会报错



// 在声明变量的时候,不注解,直接复制,那么 ts 会根据值推断变量的类型,那么这个变量以后就只能被赋相同类型的值
let c=100

// 报错
// c="asd"

// 不会报错
c=123

4. unknow 类型

// unknown 类型是一个安全的any类型,
// 因为他虽然可以被赋值任何类型的数据,但是只能赋值给unknown类型或者any类型的变量
let a:unknown;
a='123'
a=123

let c:string="safd";
// 报错 因为 c 是字符串类型,a 是 unknown类型,unknown只能赋值给unknown类型或者any类型的变量
// c=a

let d:unknown=a
let e:any=a

怎样将unknown类型赋值给上面的 c 切不报错了?有三种方式

// 第一种方式,缩小范围
if(typeof a=='string'){
    c=a
}

// 第二种方式  类型断言
c=a as string

// 第三种方式 泛型
c=<string>a

5. void 类型

// void 类型表示空   通常在限制函数没有返回值的时候使用

function func1(x: number, y: number):void{
    console.log(x,y);
    
    // 这一行报错
    // return x+y
}

6. never 类型

// never 表示永远没有返回值

function fun():never{

    throw new Error("error"); // 抛出错误之后,这行代码之后的代码就永远不会执行了,所以never不会报错

}

7. 对象类型

类型推断的方式
// 这里赋值的时候,类型就已经固化了, 就只能赋值初始化的时候的类型的值
let person={
    name:'zrs', // 这里已经推断为 person.name 为字符串了
    age:21 // 这里已经推断 person.age 为数字类型了
}

// 因为上面已经推断了 那么这里person.name 就只能是字符串了
person.name = 'aaa'

// 因为上面已经推断了 那么这里person.age 就只能是数字了
person.age =22
类型注解的方式
// 对象的类型注解的方式
let person:{name:string, age:number,sex:string}

person={
    name:'zrs',
    age:12,
    sex:'男'
}
// 以上这种方式有一个缺点,就是补不能在添加属性了
// 所以下面这句代码报错了
// person.money=222
// 在属性值后面 添加了一个 问号 表示这个属性值是可选的,就是可有可无
let person:{name:string, age?:number,sex?:string}

// 不会报错 因为 age 和 sex 可有可无
person={
    name:'zrs',
}
// propName 的类型为string 属性值的类型为any
let person:{name:string, [propName:string]:any}

person={
    name:'zrs',
    age:20,
    sex:'男',
    money:222
}

person.sex='女'
console.log( person.sex);

// 以上这种方式,可以在对象有很多个不确定属性的时候使用

8. 函数

// 普通函数的声明
/**
 * c的后面添加了一个问号,所以可有可无
 * 限制返回值是一个number类型
 */
function fun(a:number, b:number, c?:number):number {
    return a+b
}
console.log(fun(1,2));



// 箭头函数的声明
const func2=(a:string, b:string, c?:string):string =>{
    return a+b;
}

// 箭头函数的声明
const func1:(a:string, b:string, c?:string) => string=(a1:string, a2:string, a3?:string)=> a1+a2+a3

9. 匿名函数

// 匿名函数

let nums:number[] = [1,3,2,5,24,5,2,3,53,3,123,0];

// 匿名函数 可以写 参数以及返回函数的类型注解  
// 这行代码不会报错
// nums.sort((a:number, b:number):number => { return a-b; });

// 也可以不写注解,机制会自行推断
// 这行代码也不会报错
nums.sort((a, b) => { return a-b; });

console.log(nums);

10. 联合类型

|
// 之前声明的变量只能有一种类型
let uname: string='zrs'

// 但是联合类型就可以使变量有多种类型
let demo:number|string
demo=0
demo='zrs'
// 以上代码不会报错

// 定义一个变量保存函数的返回值
let flag:boolean|null|undefined
flag=false
flag=null
flag=undefined
// 以上代码不会报错

// 联合声明在函数中使用
function func(a:number|string,b:number|string):void|number{

}

// 联合类型在数组中使用
// let arr:number[]=[1,2,'12'] // 报错
let arr:number[]=[1,2] // 这种方式声明的数组只能存放一种类型的元素

// 联合类型的数组声明
let arr2:(number|string)[]=[12,'qwer'] 
arr2.push("asdf")
arr2.push(123)

console.log(arr2);
&
// 一个变量怎么能既是字符串类型又是数字类型了,这个代码就是没有意义的,虽然不会报错
let uname:string&number; 

//  & 一般适合用在这儿了
let person:{name:string} &{age:number}

person={
    name:'zrs',
    age:12
}

console.log(person);

11. 字面量类型声明

// 变量的字面量声明的方式
let a:10 // 这行代码相当于声明一个变量 变量的值只能是10
a=10
// a=11  // 这种情况的话 a会报错

// 字面量声明类型的应用场景 
let sex:'male'|'female'
sex='male'
sex='female'

console.log(sex);

12. 元组 tuple

// 声明一个数组
let arr:number[] = [];
/**
 * ts中元组是什么?
 *      元组是不同类型的元素组成的数组
 */
// 声明一个元组
// 元组的每一个元素的数据类型是意义对应的
let  mytuple:[string, number] = ['as',1];
// let  mytuple:[string, number] = [1,'as']; // 报错

// 元组定义之后,只能添加其声明的时候的数据类型,添加其他类型会报错
mytuple.push('a')
console.log(mytuple);

mytuple.pop()

mytuple.push(100)
// mytuple.push(true) //报错

console.log(mytuple);

// 数组嵌套元组---以后可能会用到
let arr4:[string, number][]=[['a',1],['b',1],['c',1],['d',1]]

13. 枚举 enum

// 限制一个变量只能是固定的几个值,可以使用字面量的方式
let sex:'male'|'female';
sex='male'
sex='female'
// sex==10 // 报错,因为 声明的是字面量类型,导致只能赋值为 'male'或者'female'
// console.log(sex);

// 当然,还有一种方式可以实现,那就是枚举
enum sex2{
    male,
    female
}

// 调用
// console.log(sex2.male);  // 0
// console.log(sex2.female); // 1

console.log(sex2[0]); // male
console.log(sex2[1]);  // female

14. 类型别名

// 类型别名  使用关键字  type

// 字面量变量的类型别名
type sex='male'|'female'
let userSex:sex='male'
console.log("userSex:",userSex);

// 函数的类型别名 
// 给注解取一个别名
type func=(a:number,b:number)=>number

// 利用别名来声明函数 这里的func 类似于声明简单数据类型后面的number/string
const getSum:func=(c,d)=>c+d
console.log("getSum:",getSum(1,1));

// 对象的别名
type person={
    name:string,
    age:number,
}

// 利用对象的别名声明对象
let parent1:person={
    name:'zrs',
    age:20
}

// 利用对象的别名声明对象
let son1:person={
    name:'zzz',
    age:12
}

// 别名就是将一种注解,赋值给某个值,然后这个值可以复用,可复用的值就是别名

15. 类型断言

/**
 * 什么是类型断言
 *      类型断言就是告诉 ts 这个变量就是这个类型,不需要你去推断了。
 */

function getSum(a:number|string){

    let len1:number;
    // 这种方式是缩小类型范围  
    // if(typeof a == "string"){
    //     len1= a.length
    // }else{
    //     len1=0
    // }

    // 类型断言的尖括号语法
    // len1=(<string>a).length

    // 类型断言之 使用 as 语法 
    len1 = (a as string).length
    console.log(len1);

}
getSum('asdfghj')


// 字面量类型的变量和常量之间的区别
// 字面量类型的变量,可以再赋值,但是只能是声明的时候的那个值
let myname:'zrs'
myname='zrs'

// const 声明的不能再赋值
const myname2:string='abcd'
// myname2='abcd'  // 报错



/**
 * 使用 const 为数据做类型断言,很常用,将当下的数据的类型转换为固定的类型
 *    根据具体的值转化类型
 */

// 将推断类型转化为字面量类型
let uname='asdc' as const

// uname='sdaf' //报错
// 因为 上面的语句将其转换为 字面量类型了,所以只能赋值为 'asdc'
uname='asdc' 

console.log(uname);

// 将推断类型的数组转化为元组
let arr=['asdds',1,'sad',22] as const
// arr[0]='asdds'  // 报错,只读,不能更改

// 将推断类型的数组转化为元组-第二种方式
let arr2=<const>['asd',12]
// arr2[0]='asd' // 报错,只读,不能更改


// 将推断类型的对象转换为只读
let  obj={
    uname:'zrs',
    age:12
} as const

// obj.uname='zrs' // 报错 只读 不能更改

function fun(){
    let str:string='qwertyuiop'
    let funSub=(a:number,b:number)=>a+b

    return [str,funSub]
}

// let [str,funSub]=fun()

// 报错  没有类型断言,所以ts不知道funSub 是函数还是字符串
// funSub()

// 这里做了类型断言,所以不会报错,ts可以正确执行代码 这是第一种方法
// 赋值的时候断言
// let [str,funSub]=fun() as [string,Function]
// console.log(str);
// console.log(funSub(10,10));

// 第二种方式,在使用的时候断言
let [str,funSub]=fun() 
console.log(str as string);
// console.log((funSub as Function)(20,20)); // 使用的时候,第一种方式断言 
console.log((funSub as (a:number,b:number)=>number)(20,20)); // 使用的时候,第二种方式的断言



// 以上方法都是在得到结果之后断言的,不方便
// 在返回的时候,直接断言最合适
function fun2(){
    let str:string='qwertyuiop12345678'
    let funSub=(a:number,b:number)=>a+b

    // return [str,funSub] as[string,Function]  // 第一种方式
    // return [str,funSub] as[typeof str,typeof funSub]  // 第二种方式
    return  [str,funSub] as const  // 第三种方式
}
let [str2,funSub2]=fun2() 
// let [str2,funSub2]=fun2() as const  // 报错 因为这里是返回的值,已经不能明确类型了
console.log(str2 );
console.log((funSub2)(100,30))

为什么会有类型断言这种玩意儿?

  • 因为在声明变量的时候,有联合类型等,导致ts不知道对应的变量的具体类型,所以需要手动告诉ts该变量是什么类型。

非空断言

let str:string='zrs'
// 因为我在 tsconfig.json 中配置了  "strict": true,   所以下面的语句报错
// str=null
// str=undefined

// 非空断言
let str2:string|null|undefined;

str2='asdfghjkl'

console.log(str2!.length);

/**
 * 在 变量后面添加 ? 表示这个变量可有可无
 * 在 变量后面添加 !  表示告诉ts这个变量一定是非空值
 */

16. 函数类型

// 给函数一个注解
let fun:(a:number,b:number)=>number=(n:number,m:number)=>{
return 10
}

// 使用别名的方式
type myfun=(a:number,b:number)=>number

let fun2:myfun=(n,m)=>{
    return n+m
}

// 回调函数使用类型注解  使用的是别名的方式
function calc(a:number,b:number,fun:myfun){
    return fun(a,b)
}


let res=calc(10,21,(n,m)=>{
    return  n+m
})

console.log(res);

// 对象中定义的函数的注解
let person:{
    uname:string,
    age:number,
    fun:(a:number,b:number)=>void
}

 person={
    uname:'zrs',
    age:18,
    fun:(a,b)=>{
        console.log(a+b); 
    }
}
person.fun(10,11)


type user={
    uname:string,
    age:number,
    func:(n:number,m:number)=>void
}

const person1:user={
    uname:'zrs',
    age:20,
    func:(n,m)=>{
        console.log(n+m);
    }
}

函数的可选参数

// 可选参数
type func = (a: number, b?: number) => number

// 再参数后面添加一个 ?表示这个参数是可选的,表示可有可无
const myfun: func = (n: number, m?: number) => {
    if (typeof m === "number") {
        return n + m
    }
    return n
}

let res = myfun(1, 1)
console.log(res);

// 函数的参数的默认值
const myfun2 = (a: number = 1, b: number = 2): void => {
    console.log(a, b);
}
myfun2()
myfun2(3, 4)

// 函数的可变参数(剩余参数) 使用扩展运算符
// 这里的第三个参数是一个展开的任意类型的数组 用来接收剩余的参数 
const myfunc3 = (a: number, b: number, ...args: any[]): void => {
    console.log(a, b, args);
}
myfunc3(1, 2, 3, 4, 'qwertyui')

函数的重载

// 函数的重载

/**
 * 函数重载就是 同一个函数名 因为参数类型不同,或者参数类型的顺序不一样而执行不同的函数体的情况
 */

// 可以这样理解 先定义一个框架,没有写方法体
function fun(a: number, b: number): number
function fun(a: string, b: string): string
function fun(a: number, b: string): string

function fun(a: any, b: any) {
    console.log("a", a, "b", b);
    return a + b
}

fun(10, 12)
fun('s', 'sdddd')
fun(11, 'asdf')

17. 类

// ts 中类的写法
class Person {
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    eat() {
        console.log(this.name + "正在吃饭", this.age + "岁");
    }
}

const p1 = new Person('zrs', 20)
p1.eat()
console.log(p1.name);
console.log(p1.age);


// 类的继承(又叫做类的扩展)
// ts 中类的继承
class Son extends Person {
    money: number
    hobby: string
    constructor(name: string, age: number, money: number, hobby: string) {
        super(name, age)
        this.money = money
        this.hobby = hobby
    }
    study() {
        console.log(this.name + "正在学习");
    }
}

const s1 = new Son('zts', 11, 1000, '打篮球')
s1.study()

// ts 中方法的重写
/**
 * 什么是方法的重写?
 *  就是在子类中写一个与父类中名字一样的方法,用来覆盖父类中的方法,叫做重写
 *  一般在父类的方法不能满足子类的使用要求的时候调用
 *  那么又想要调用父类被覆盖的方法又怎么办?使用 super.父类中被重写的方法() 即可
 */

class Sister extends Person {
    sex: string
    constructor(name: string, age: number, sex: string) {
        super(name, age)
        this.sex = sex
    }
    // 重写父类中的 eat() 方法
    eat() {
        console.log("先吃饭再学习");
        console.log(this.name + "吃完饭了,去学习去了");
    }
    BigDinner() {
        // 这里调用父类中被重写的方法 eat
        super.eat()
        console.log("吃大餐");
    }
}

const s2 = new Sister('zzz', 11, '女')
s2.eat()
s2.BigDinner()

类的访问修饰符

public
// 类中的访问修饰符
/**
 * 类中的访问修饰符有:
 *  public  =>公共的
 *  private => 私有的
 *  protected =>受保护的
 *  readonly  =>只读
 */


/**
 * public 限制下 
 *  可以在类的内部访问修改
 *  可以在类的外部访问修改
 */
class Person {
    public name: string
    public age: number
    public constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }

    public say() {
        console.log("my name is  " + this.name);
    }
}

const p1 = new Person('zrs', 20)

p1.say()
private
/**
 * private 限制下的属性和方法 只能在自己中访问修改
 */
class Person {
    private name: string
    private age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }

    say() {
        /**
         * private 限制下的属性和方法 只能在自己中访问修改
         */
        this.name = "小张"
        console.log("my name is  " + this.name);
    }
}

const p1 = new Person('zrs', 20)

p1.say()
// p1.name="zrs1111" // 报错 私有属性,只能在类中访问
// console.log(p1.name); // 报错 私有属性,只能在类中访问
protected
/**
 * protected =>受保护的  限制的属性和方法 只能在自己和自己的孩子类中访问和修改
 */
class Person {
    protected name: string
    protected age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    say() {
        this.name = "小张"
        console.log("my name is  " + this.name);
    }
}

const p1 = new Person('zrs', 20)

p1.say()
// p1.name='zrs2222'  // 报错 只能在类中或者子类中访问
// console.log(p1.name); // 报错 只能在类中或者子类中访问

class Son extends Person {
    hobby: string
    constructor(name: string, age: number, hobby: string) {
        super(name, age)
        this.hobby = hobby
    }
    eat() {
        console.log("我是  " + this.name + "   我正在吃饭");
    }
}

const s1 = new Son("小小张", 1, "rap")

s1.eat()
// s1.name = '小小小张'  // 报错 因为父类使用了 protected 限制,只能在父类或者子类中访问
// console.log(s1.name);  // 报错 因为父类使用了 protected 限制,只能在父类或者子类中访问
readonly
/**
 * readonly  =>只读   该修饰符的限制下,只能被初始化一次 然后就不能修改了
 */
class Person {
    readonly name: string
    readonly age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    say() {
        // this.name = "小张"  // 报错 因为这个是只读属性,只能初始化的时候赋值一次
        console.log("my name is  " + this.name);
    }
}

const p1 = new Person('zrs', 20)

p1.say()
// p1.age=20   // 报错只读属性
console.log(p1.name);  // 可以访问,不能修改
声明的类也可以作为一个类型
/**
 * 将类作为另一个类的属性的类型
 */
class Phone {
    brand: string
    constructor(brand: string) {
        this.brand = brand
    }
}

class Person {
    name: string
    age: number
    phone: Phone   // 将类作为一另一个类的属性的类型  
    constructor(name: string, age: number, phone: Phone) {
        this.name = name
        this.age = age
        this.phone = phone
    }
    say() {

        console.log("my name is  " + this.name);
    }
}

const p1 = new Person('zrs', 20, new Phone('huawei'))

p1.say()

console.log(p1.phone.brand);

p1.phone.brand = "huawei 99"

console.log(p1.phone.brand);
ts 中的类的属性和方法的封装
/**
 * 面向对象有四大特点:
 *  封装
 *  继承
 *  多态
 *  抽象
 */

/**
 * 利用类的修饰符,可以实现对类的属性和方法的封装
 *  为什么要进行封装?
 *      将有用的东西暴露给用户,其他的东西就自己藏起来。
 */

class Person {
    name: string
    private _sex: string
    constructor(name: string, sex: string) {
        this.name = name
        this._sex = sex
    }

    // ts 中提供的setter 设置值专用
    set setSex(sex: string) {
        this._sex = sex
    }
    // ts 提供的getter 获取值专用
    get getSex() {
        return this._sex
    }

    set setName(name: string) {
        this.name = name
    }

    get getName() {
        return this.name
    }

    run() {
        console.log("运动");
        this.go()
        this.back()
    }

    private go() {
        console.log("前进");
    }
    private back() {
        console.log("后退");
    }
}

const p1 = new Person('zrs', '男')

p1.run()

console.log(p1.getSex);
p1.setSex = "nv"
console.log(p1.getSex);

static
// 类中 static 使用

/**
 * 在类的属性和方法前面添加 static 这个属性或者方法就变成了 静态属性和方法,为这个类所有
 */

class Student {
    // 静态属性
    static school: string = "cczx"
    name: string
    constructor(name: string) {
        this.name = name
    }
    static sayMySchool() {
        // 在静态方法 中调用静态属性或者方法 使用 this.属性名或者方法名 这里的this指向的是 Student 不是类实例化的对象
        console.log("我的学校是" + this.school);
    }
    say() {
        // 在非静态的方法中使用 静态属性或者方法  语法:类名.静态属性或者方法
        console.log("我是" + this.name + "我是" + Student.school + "的");
        // 非静态方法中的this指向的是实例化之后的对象
    }
}

Student.sayMySchool()
console.log(Student.school);

const s1 = new Student('zrs')
/**
 * 类中的静态属性和方法,对象不能直接使用的
 */
// s1.school  // 报错

s1.say()

18. 抽象类

/**
 * 抽象类
 *  抽象类是一个特殊的类,一个类中如果有一个抽象方法,那么这个类就是抽象类。
 *  抽象类不能实例化
 * 
 * 抽象方法
 *  抽象方法没有方法体。
 */

// 使用 abstract 来声明一个抽象类
abstract class Person {
    name: string = 'zrs'
    // 抽象属性
    abstract money: number
    say() {
        console.log("hello");

    }

    // 抽象方法  因为类中有一个抽象方法,所以类的前面也必须添加 abstract
    abstract run(): void

    // 抽象方法
    abstract back: () => void
}

/**
 * 抽象类可以被继承,但是继承之后的类依然需要是抽象类,否则需要将继承的抽象类中的方法或者属性全部实现
 */


// 抽象类 继承 抽象类
abstract class Son extends Person {
    sex: string
    constructor(sex: string) {
        super()
        this.sex = sex
    }
}

// 使用正常的类继承抽象类
// 这个类就可以实例化了
class Student extends Person {
    money: number;
    constructor(money: number) {
        super()
        this.money = money
    }
    // 实现 父抽象类的方法
    run(): void {

    }
    // 实现 父抽象类的方法
    back: () => void = () => {

    }
}
const s1 = new Student(1000)

19. 接口

接口的单继承,多继承,使用类实现接口

// 接口  interface

/**
 * 接口是抽象类中的特殊种族 这里面所有的属性和方法都只有声明,没有实现
 */
interface Person {
    name: string
    run: () => void
    back(): void
}
interface Phone {
    brand: string
}

// 接口的单继承
interface Parent extends Person {
    money: number
}

// 接口的多继承
interface Stuent extends Person, Phone {
    school: string
}

//  使用类 来实现接口
class Father implements Parent {
    name: string
    money: number
    constructor(name: string, money: number) {
        this.name = name
        this.money = money
    }
    run(): void {

    }
    back(): void {

    }
}

const f1 = new Father('zrs', 10000)

20. 多态

// 多态
/**
 * 多态就是将接口预留好,后面直接写代码实现,然后调用
 */
interface USB {
    start(): void
    run(): void
    end(): void
}

function demo(u: USB) {
    u.start()
    u.run()
    u.end()
}

class ShuBiao implements USB {
    start(): void {
        console.log("开启");
    }
    run(): void {
        console.log("正常运行");
    }
    end(): void {
        console.log("结束");
    }
}

demo(new ShuBiao())

21. 接口的灵活运用

// 使用别名不能声明重名的
type  obj={
    name:string,
    age:number
}

// type  obj={}  // 报错

const  o1:obj={
    name:'zrs',
    age:12
}

// 重名的接口会合并
interface  obj1{
    name:string
}
interface  obj1{
    age:number
}
const  o2:obj1={
    name:'zrss',
    age:10
}

// 以上方式都限制了 实例化之后的属性的个数,下面这种方式将不会限制属性的个数
interface  obj2{
    [index:number]:string
}
// 对象里可以添加任意多个符合要求的属性和属性值
const  o3:obj2={
    1:'姓名',
    2:'性别'
}

// 对象里可以添加任意多个符合要求的属性和属性值
interface  obj3{
    [key:string]:string
}
const  o4:obj3={
    name:'zzr',
    age:'12'
}

22. 泛型

/**
 * 泛型,就是在定义的时候不指定类型,在使用的时候指定类型
 */
/**
 * 泛型参数化
 */
function fun<T>(a:T,b:T):T {
    console.log(a,b)
    return  a
}
// 在使用的时候指定类型
fun<number>(10,11)
fun<string>('asd','wer')

// 在声明的时候也可以指定多个泛型
function fun2<A,S,D>(a:A,b:S,c:D) {
    console.log(a,b,c)
}
// 调用的时候指定类型
fun2<number,string,boolean>(1,'qwert',true)

/**
 * 泛型的默认值
 */
//   T=number  就是泛型的默认值
function fun3<T=number>(args:T){
    console.log(args)
}
fun3(11)
fun3<string>('sdf')

/**
 * 类型的约束
 */
interface  ILength{
    length:number
}

// 让这个泛型 去继承 接口 保证传入的值有一个length属性
function func4<T extends  ILength>(args:T){
    console.log("func4",args.length)
}
func4('abc')
func4([1,2,3,4])
func4({name:'zrs',length:123})


/**
 * 泛型的接口
 */
interface  IPerson<T1=string,T2=number>{
    name:T1,
    age:T2
}

// 使用泛型的默认值
const  p1:IPerson={
    name:'zrs',
    age:12
}

// 指定泛型的类型
const  p2:IPerson<string,string>={
    name:'zrs',
    age:'12'
}

// 创建泛型的类
class Person<T1,T2> {
    name:T1
    age:T2
    sex:T1
    constructor(name:T1,age:T2,sex:T1) {
        this.name=name
        this.age=age
        this.sex=sex
    }
}
// 实例化的第一种方式 让其自行推断
const  p5=new Person('asd',12,'male')

// 实例化的第二种方式
const  p6=new Person<string,number>('asdf',122,'male')

// 实例化的第三种方式
const p7:Person<string,number>=new Person('asd',1,'male')

// 第三种方式类似于数组的泛型声明
const  arr:Array<number>=[]

23. ts中的命名空间

// 命名空间
// demo2.ts 文件
// 跨文件的命名空间也需要导出 才可以使用
export namespace login{
    export  function fun(flag:boolean){
        if(flag){
            console.log("登录成功")
        }else{
            console.log("登录失败")
        }

    }

}

// demo1.ts 文件
/**
 * 命名空间
 */
import  {login} from './demo2'
// 命名空间是为了解决命名冲突的问题
namespace uname{
    // 命名空间中函数,变量 都需要 使用 export 导出才可以在外面使用
    export  function fun<T1>(args:T1){
        console.log(args)
    }
    export  const PI:number=3.1415926
}

namespace  product{
    export  function  fun(args:number){
        console.log(args)
    }
    // 注意: 嵌套的命名空间也需要导出
    export namespace list{
        export   let name:string='zrs'
    }
}
// 使用命名空间之内的函数,变量
uname.fun<number>(12313213)
product.fun(9876)
console.log(uname.PI)

// 调用嵌套的命名空间
console.log(product.list.name)

// 多个文件的命名空间使用 需要先导入文件
login.fun(false)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值