30Vue-TS

90 阅读4分钟

认识泛型

图片.png

//在定义这个函数时,我不决定这些函数的类型
//而是让调用者 以参数的形式告知 这里的函数参数应该是什么类型
function sum<Type>(num1:Type):Type{
    return num1
}
//告诉函数,我要传以number类型的数据作为形参
sum<number>(20)

//告诉函数,我要传一个对象类型的参数,作为形参
sum<{name:string}>({name:"why"})

//数组类型,并且数组中数据是任意类型
sum<any[]>(["abc"])


//不写具体类型,直接传参,TS会自动推导,默认推导出是字面量类型
sum(50)

接收多个类型参数

//T是Type的缩写
function foo<T,E>(arg1: T, arg2: E){

}

foo<number,string>(10,"abc")

接收剩余参数

function foo<T,E>(arg1: T, arg2: E,...args:T[]){

}

//因为剩余参数用的是T,所以这里必须保持一致用number类型
foo<number,string>(10,"abc",1,2,3,4,5,6)

图片.png

泛型就是让 使用者自己把控数据类型 ,如果已经确定数据类型了,其实不需要用泛型

泛型接口

//接口里面用到的类型是让用户自己决定的
//可以自己设置默认类型,后续使用如果不指定类型,就用默认类型
interface IPerson<T1=string,T2=number>{
    name: T1
    age: T2
}

//接口这里 没有类型推导,必须要自己指定
const p:IPerson<string,number> = {
    name:"why",
    age:18
}

泛型类的使用

class Point{
    //x:number
    //y:number
    //z:number
      x:T
      y:T
      z:T
    constructor(x:T,y:T,z:T){
        this.x = x
        this.y = y
        this.z = z
    }
}
//这里的T 泛型为 number(类型推导)
const p = new Point(1,2,3)
//也可以自己指定
const p = new Point<number>(1,2,3)

//指定对象 是一个类的类型并且类的类型为泛型 类型
const p:Point<number> = new Point(1,2,3)

//数组类型
const name: string[] = ["abc","cba","nba"]

//这两种写法是等价的,但是这种写法更像泛型(不推荐)
const name: Array<string> = ["abc","cba"]

泛型的类型约束

function getLength<T>(arg: T){
//其实这样写是会有问题的,万一我传来的是number类型,他是没有length属性的
    return arg.length
}

需要对类型进行限制
interface ILength{
    //接口里面存储的是对象类型,要求有一个这样的对象属性才可以。
    length:number
}
function getLength<T extends ILength>(arg: T){
    return arg.length
}
getLength(123)
//不给你传,因为ILength接口中定义了length属性
//但是number类型中,不存在length属性,更别说是不是number类型了


getLength("abc")//可以传,因为他有length属性,并且length属性是number类型

getLength(["abc","cba"])//数组里也是有length属性的

getLength({length:100})//对象里书写了length属性

TypeScript其他内容补充

模块化开发

图片.png

模块 math.ts

封装了一个独立的模块,将两个函数导出
export function add(num1:number1,num2:number){
    return num1 + num2
}

export function sub(num1:number1,num2:number){
    return num1 - num2
}

main.ts

导入模块
import {add,sub} from './math'
    console.log(add(20,10))
    console.log(sub(20,10))

命名空间

format.ts

一个文件里有不同功能,但是相同命名的方法
除了避免命名,也可以命名空间
export function format(time: string){
    return "2222-02-22"
}

export function format(price: number){
    return "99.99"
}
------------------------------------------
namespace time{
    export function format(time: string){
        return "2222-02-22"
    }
    
    //命名空间里可以定义很多东西,默认属于内部,外部想要拿到,必须要export出去
    export function foo(){
        
    }
    
    export let name: string = "abc"
}

//在对命名空间进行export,就可以在其他文件中import了
export namespace price{
    export function format(price: number){
        return "99.99"
    }
}

time.format
time.foo
time.name

price.format

大家能够避免同名,就避免,最好不要出现相同命名的情况。

类型查找

图片.png

图片.png

图片.png

内置类型声明

图片.png

图片.png 当我们在vscode中安装TypeScript环境时,就会创建。

外部定义类型声明

同样都是引用,为什么lodash会报错?

import axios from 'axios'//不会报错
import lodash from 'lodash'//报错了

因为TS中并没有在d.ts中 声明lodash

图片.png

自定义声明

那我想用lodash,就需要自己自定义类型声明

coderwhy.d.ts

declare module 'lodash'{
   export function join(arr:any[]):void 
}

main.ts

import lodash from 'lodash'//不会报错了

//可以使用自定义声明后的join方法
console.log(lodash.join(["abc","cba"]))

案例

自定义的.d.ts文件会转换为js文件,然后引用映射到.html文件中,最终呈现在页面上

index.html

<head></head>
<body>
    <script>
    //在html中定义的变量,本质是不可以在main.ts中使用的
    //因为TS不知道你有name、age、height,你没有声明
        let name = "why"
        let age = 18
        let height = 1.88
        
        function whyFoo(){
            console.log("whyFoo")
        }
        
        function Person(name,age){
            this.name = name;
            this.age = age;
        }
    </script>
</body>

why.d.ts(自定义声明)

//声明模块
declare let name: string
declare let age: number
declare let height: number

declare function whyFoo():void

declare class Person{
    name:string
    age:number
    constructor(name:string,age:number)
}

main.ts

console.log(name)
console.log(age)
console.log(height)

whyFoo()

const p = new Person("why",18)
console.log(p)

在index.html中书写代码,在main.ts中能够使用

声明文件

main.ts

从外部引入一张图片
import Image from '...'
本质是会报错的,因为TS不认识你这张图片

.d.ts

//将以.jpg结尾的文件,全部当成模块来使用
declare module '.*jpg'

后续再在main.ts中引入就可以了 import Image from '.jpg'

声明命名空间

在我们的项目中引入JQuery,就需要用到命名空间

在.d.ts中

//因为我本身也有$,所以要用命名空间 解决重复命名
declare namespace ${
    export function ajax(settings:any):any
}

main.ts

$.ajax({
    
})

总结

不管在TS中使用什么,前提:必须要被TS声明。可以来自内置类型声明、外部类型声明、自定义类型声明。