ts学习笔记

TypeScript

本文引用枫枫知道不做商用,仅用于学习枫枫知道

可以购买枫枫知道的课程

安装node

建议下载长期维护版

安装之后把node加入环境变量

命令行输入 node -v npm -v

npm就是node里面安装第三方包的工具,相当于pip

安装tsc

它的作用就是将ts文件编译为js文件

// .ts => .js
npm i typescript -g
tsc -v
tsc --init              // 生成一个json文件
tsc                     // 会编译项目目录下所有的ts文件
tsc xxx.ts              // 只编译xxx.ts文件
tsc -w xxx.ts           // 监听xxx.ts  只要保存就编译
node hello_world.js     // 执行

安装ts-node

npm i ts-node -g
ts-node xxx.ts      // 直接运行xxx.ts

hello world

// hello_world.js
const hw :string  = "hello_world"
console.log(hw)
// cmd
tsc --init              // 生成一个json文件
tsc                     // 会编译项目目录下所有的ts文件
tsc xxx.ts              // 只编译xxx.ts文件
tsc -w xxx.ts           // 监听xxx.ts  只要保存就编译
node hello_world.js     // 执行

ts基本类型

数字类型 number

可以是整数,小数,十六进制,八进制,二进制数

let n1 : number = 1  
let n2 : number = 1.56
let n3 : number = 0xf
let n4 : number = 0o7
let n5 : number = 0b01
let n6 : number = NaN

字符串类型 string

let s:string = "枫枫"

布尔类型 boolean

let b1 :boolean = true
let b2 :boolean = false

空类型

null,undefined,void

  • null 指空值(empty value)

  • undefined 指没有值(missing value)

    或者:

  • undefined 指从未赋值

  • null 指曾赋过值,但是目前没有值

    null 是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。然而

    undefined 却是一个标识符,可以被当作变量来使用和赋值

  • void是没有返回值

严格模式下 >>> tsc --init 生成的json文件中 strict:true false是关闭严格模式

null,undefined它们两个不能相互赋值

let u1: null = null
let u2: undefined = undefined

关闭严格模式,它们就可以相互赋值

let u3: null = undefined
let u4: undefined = null

function setName(name:string):void{
    return
}
function setName(name:string):void{
    return 1  // 错误
}

any

使用any类型,ts就会关闭类型检查,这样就和写js一模一样了,尽量少用

let a1 : any = "123"
a1 = 13
a1.name = "xxx"
a1.push("123")

unknown

和any的区别

不能点属性

联合类型和类型断言

联合类型

function getNum(num:string|number):number{
    return 1
}
getNum(123)
getNum("354")

let div:HTMLElement|null = document.getElementById("#div")
function clearTimeout(id: number | undefined): void;  // 定时器清除

类型断言

就是认为将某一种不确定的类型断言为确定的类型

只是在编辑器层面进行的欺骗行为

let img = document.getElementById("#img")
img.src = "http://xxx.xxx/img"  // 报错
// ---------------------------
let img = document.getElementById("#img") as HTMLImageElement
img.src = "http://xxx.xxx/img"

let img = document.getElementById("#img")
img.src = "http://xxx.xxx/img"
  • 两种写法

    value as Type
    value
    
    document.getElementById("#img") as HTMLImageElement
    document.getElementById("#img")
    function getAny():any{
        return ""
    }
    let s = (getAny()as string).charAt()
    let s = (getAny()).charAt()

数组类型

数组定义

一般来说,数组里面的元素都应该是同类型的

let a1:string[] = ["e634"]
let a2:boolean[] = [false, true]
let a3:Array = [1,5,6,7]

杂乱数组

let a4:any[] = [1, "s", [123, [13]]]
let a5:(string|number)[] = [1,2,"345"]

元组

let a7: [number, number] = [1, 2]
console.log(a7[2]) // 防止越界

let a8:[1,string, true] = [1, "", true]
let scope: [string, number, number, number] = ["小明", 12, 45, 23]

多维数组

let arr1: number[][] = [[1, 2], [12]]
let arr2: Array> = [[1], [2]]

interface

接口定义

interface UserInfoFace {
    name: string
}
let zhangsan :UserInfoFace = {
    name: "张三"
}
console.log(zhangsan.name)

可选属性

interface UserInfoFace {
    name: string
    age?:number
    addr?:string
    like?:string[]
}

let zhangsan :UserInfoFace = {
    name: "张三",
}
zhangsan.age = 23
console.log(zhangsan.name)

只读属性

interface UserInfoFace {
    readonly id: number
    name: string
    age?:number
    addr?:string
    like?:string[]
}

let zhangsan :UserInfoFace = {
    id: 1,
    name: "张三",
}
console.log(zhangsan.id)
// zhangsan.id = 12 // 不能修改
zhangsan.age = 23
console.log(zhangsan.name)

添加方法

interface UserInfoFace {
    readonly id: number
    name: string
    age?:number
    addr?:string
    like?:string[]
    getName: ()=>string
    setAge: (age:number)=>void
}

let zhangsan :UserInfoFace = {
    id: 1,
    name: "张三",
    getName: function ():string{
        return this.name
    },
    setAge:function (age:number){
        this.age = age
    }
}
console.log(zhangsan.id)
// zhangsan.id = 12 // 不能修改
// zhangsan.age = 23
zhangsan.setAge(21)
console.log(zhangsan.age)
console.log(zhangsan.getName())
console.log(zhangsan.name)

继承 extends

interface People {
    gender: number // 0 女 1 男  2 未知
}
interface UserInfoFace extends People{
    readonly id: number
    name: string
    age?:number
    addr?:string
    like?:string[]
    getName: ()=>string
    setAge: (age:number)=>void
}

let zhangsan :UserInfoFace = {
    id: 1,
    name: "张三",
    getName: function ():string{
        return this.name
    },
    setAge:function (age:number){
        this.age = age
    },
    gender: 1
}
console.log(zhangsan.id)
// zhangsan.id = 12 // 不能修改
// zhangsan.age = 23
zhangsan.setAge(21)
console.log(zhangsan.age)
console.log(zhangsan.getName())
console.log(zhangsan.name)

交叉类型

会将两个类型中的属性合并

interface People {
    gender: number // 0 女 1 男  2 未知
}
interface UserInfoFace {
    readonly id: number
    name: string
    age?:number
    addr?:string
    like?:string[]
    getName: ()=>string
    setAge: (age:number)=>void
}

let zhangsan :UserInfoFace & People = {
    id: 1,
    name: "张三",
    getName: function ():string{
        return this.name
    },
    setAge:function (age:number){
        this.age = age
    },
    gender: 1
}
console.log(zhangsan.id)
// zhangsan.id = 12 // 不能修改
// zhangsan.age = 23
zhangsan.setAge(21)
console.log(zhangsan.age)
console.log(zhangsan.getName())
console.log(zhangsan.name)

类型别名

类型别名的用法

type nameType = string | string[]

let zhangName :nameType = "张三"
let zhangName1 :nameType = ["张三"]

可以用来定义函数

type fn = (name: string, age: number) => string
let fn1: fn = function (name: string, age: number): string {
    return "xxx"
}
let fn2: fn = (name: string, age: number): string => "xxx"

也可以用来定义对象

type infoType = {
    readonly name: string,
    age?: number
}
let zhangsan:infoType = {
    name: "张三",
}

和interface的区别

  1. interface可以继承 type 只能通过 & 交叉类型合并

interface I1{
    name: string
}
interface I2 extends I1{
    age: string
}

type T1 = {
    name: string
}
type T2 = {
    age: number
}
let t:T1&T2 = {
    name:"张三",
    age: 12
}
  1. type 可以定义 联合类型 和 可以使用一些操作符 interface不行

type nameType = string|string[]
  1. interface 遇到重名的会合并 type 不行

interface A1 {
    name: string
}
// 遇到相同的会合并
interface A1{
    age: number
}
let a1:A1={
    name:"A1",
    age: 13
}

type A1 = {
    name: string
}
// 会直接报错
type A1 ={
}

函数类型

函数类型定义

基本定义

function add1(n1:number, n2:number):number{
    return n1 + n2
}

let add2 = (n1:number, n2:number):number=>{
    return n1+n2
}

函数参数

可选参数

在参数名的后面,加一个?,表示该参数可选,如果不传,那这个参数就是undefined

并且在实际使用中,要进行类型判断

function add(n1:number, n2?:number):number{
    if (typeof n2 === "undefined"){
        return n1
    }
    return n1 + (n2 as number)
}

// 要么不传,要么传正确的类型
add(1)
add(1, 2)
add(1, "3") // 报错

默认值

function add(n1:number, n2:number = 10):number{
    return n1 + n2
}

console.log(add(1))  // 11
console.log(add(1, 2)) // 3

默认值和可选参数不能同时出现!

参数为接口类型

interface getUserListRequest {
    page?:number
    limit?:number
    key?:string
    name?:string
}
function getUserList(params:getUserListRequest){
    console.log(params.limit) // 有类型提示
}

函数重载

function addFn(n1:number, n2:number):number
function addFn(n1:number):number
function addFn(n1:number, n2:number = 10):number{
    return n1 + n2
}
console.log(addFn(1))
console.log(addFn(1, 20))

枚举

数字枚举

enum Color {
    Red, // 0
    Blue, // 1
    Green, // 2
}

let c1:Color = Color.Blue
let c2:Color = 5  // 编译会失败
let c3:Color = "234" // 直接失败

如果是纯数字,下面的会进行自动增长

自动从0开始

enum Color {
    Red=100,
    Blue, // 101
    Green, // 102
    Yellow, // 103
}

如果中断了,那么下面的就从中断的地方继续增长

enum Color {
    Red=100,
    Blue, // 101
    Green=103, // 103
    Yellow, // 104
}

字符串枚举

它不能自动增长

enum Color {
    Red="red",
    Blue, // 报错
}

如果是字符串,那么定义的时候就要全部写上

enum Color {
    Red="red",
    Blue="blue",
}

接口枚举

enum Color {
    Red,
    Blue,
    Yellow
}

interface ColorInter {
    color: Color,
    blue: Color.Blue
}

let c1: ColorInter = {
    color: Color.Red, // 这个color只能是Color里面的值
    blue: Color.Blue, // blue就只能写 Color.Blue
}

const枚举

  • 主要作用就是节省因为枚举带来的性能消耗

enum Color {
    Red = 2,
    Blue,
    Yellow
}
interface ColorInter {
    color: Color,
    blue: Color.Blue
}
let c1: ColorInter = {
    color: Color.Red, // 这个color只能是Color里面的值
    blue: Color.Blue, // blue就只能写 Color.Blue
}

编译之后

var Color;
(function (Color) {
    Color[Color["Red"] = 2] = "Red";
    Color[Color["Blue"] = 3] = "Blue";
    Color[Color["Yellow"] = 4] = "Yellow";
})(Color || (Color = {}));
var c1 = {
    color: Color.Red,
    blue: Color.Blue, // blue就只能写 Color.Blue
};
const enum Color {
    Red = 2,
    Blue,
    Yellow
}
interface ColorInter {
    color: Color,
    blue: Color.Blue
}
let c1: ColorInter = {
    color: Color.Red, // 这个color只能是Color里面的值
    blue: Color.Blue, // blue就只能写 Color.Blue
}

编译之后

var c1 = {
    color: 2 /* Color.Red */,
    blue: 3 /* Color.Blue */, // blue就只能写 Color.Blue
};

泛型

函数泛型

泛型就是把类型当做参数

需求:编写一个函数,传入两个参数,返回这两个参数组成的数组。注意,两个参数的类型必须一致

// 例如 
fun(1,2)       // => [1, 2]
fun("2", "2")  // => ["2", "2"]
// 不使用泛型
function numberArray(a1:number, a2:number):number[]{
    return [a1, a2]
}
function stringArray(a1:string, a2:string):string[]{
    return [a1, a2]
}

使用泛型

function array(a:T, b:T):T[]{
    return [a, b]
}
console.log(array(1,2))
console.log(array("1","5546"))
console.log(array(true, false))
console.log(array(null, null))
console.log(array(1,2))

多参数情况

function array(a:T, b:K):(T|K)[]{
    return [a, b]
}
console.log(array(1,"2"))
console.log(array(1,"2"))

泛型约束

比如,我希望我传入的这个参数,能够 .length

那么它的类型就应该是 string或者是数组

function array(a:T, b:T):T[]{
    console.log(a.length)
    return [a, b]
}
console.log(array("12334","2"))
console.log(array(["1", "33"],["2"]))

接口泛型

接口函数

interface Fun {
    (name: string):string
}
let fun:Fun = function (name:string):string{
    return ""
}

接口函数的泛型

interface ArrType {
    (a1: T,a2:T):T[]
}
let fun:ArrType = function (a1:string, a2:string):string[]{
    return [a1, a2]
}

属性泛型

interface Info {
    like: T
}
let zhangsan: Info = {
    like: "羽毛球"
}
let lisi: Info = {
    like: ["羽毛球"]
}

泛型约束

interface Info {
    like: T
}
let zhangsan: Info = {
    like: "羽毛球"
}
let lisi: Info = {
    like: ["羽毛球"]
}

和接口继承在一起的时候,不要搞混了

interface People {
    name?: string
}
interface Info extends People{
    like: T
}
let zhangsan: Info = {
    like: "羽毛球"
}
let lisi: Info = {
    like: ["羽毛球"]
}

keyof

interface Info {
    name: string
    age: number
}
let zhangsan:Info = {
    name:"zhangsan",
    age: 21
}
function getInfoValue(info:Info, key: string):void{
    // 这个时候,这里会报错,原因是因为传入的这个key,有可能不是Info的属性
    console.log(info[key])
}
getInfoValue(zhangsan, "name")

使用keyof

interface Info {
    name: string
    age: number
}
let zhangsan:Info = {
    name:"zhangsan",
    age: 21
}
function getInfoValue(info:Info, key: keyof Info):void{
    console.log(info[key])
}
getInfoValue(zhangsan, "name")
getInfoValue(zhangsan, "age")
getInfoValue(zhangsan, "age1") // 不满足keyof的校验,会报错

getInfoValue函数的基础上,实现将value返回

interface Info {
    name: string
    age: number
}
let zhangsan:Info = {
    name:"zhangsan",
    age: 21
}
function getInfoValue(info:Info, key: T):Info[T]{
    return info[key]
}
getInfoValue(zhangsan, "name")
getInfoValue(zhangsan, "age")

内置对象

ECMAScript 的内置对象

如果是new 对象的,它的类型就是那个对象的名字

let date: Date = new Date()
let regex: RegExp = /12/
let regex1: RegExp = new RegExp(/\s+/)
let err: Error = new Error("123")

DOM与BOM

常见的DOM类型

都在HTMLElementTagNameMap里面

"a": HTMLAnchorElement;
"body": HTMLBodyElement;
"button": HTMLButtonElement;
"canvas": HTMLCanvasElement;
"div": HTMLDivElement;
"footer": HTMLElement;
"form": HTMLFormElement;
"h1": HTMLHeadingElement;
"head": HTMLHeadElement;
"header": HTMLElement;
"html": HTMLHtmlElement;
"title": HTMLTitleElement;
"input": HTMLInputElement;
"img": HTMLImageElement;
const body: HTMLElement = document.body;
const divList: NodeList = document.querySelectorAll('div');
document.addEventListener('click', (e: MouseEvent) => {
});
let l :Location = location
let s:Storage = localStorage
let s1:Storage = sessionStorage
let c:string = document.cookie

Promise

使用fetch 请求一个json文件,把响应的数据显示出来

json文件

interface dataType {
    name: string
    age: number
}
interface responseType {
    code: number
    data: T[]
    msg: string
}
fetch("/data.json").then((response: Response) => response.json()).then((res: responseType) => {
    //返回一个Promise对象,要用.then()
    let app = document.getElementById("app") as HTMLDivElement
    res.data.forEach((item: dataType) => {
        let li = document.createElement("li")
        li.innerHTML = `
        name: ${item.name} age:${item.age}`
        app.append(li)
    })
})

改成以下这种

interface dataType {
    name: string
    age: number
}
interface responseType {
    code: number
    data: T[]
    msg: string
}
async function getList():Promise>{
    let response = await fetch("/data.json")
    // 一个await相当于一个.then()
    return response.json()
}
async function getData(){
    let res:responseType = await getList()
    let app = document.getElementById("app") as HTMLDivElement
    res.data.forEach((item:dataType)=>{
        let li = document.createElement("li")
        li.innerHTML = `
        name: ${item.name} age:${item.age}`
        app.append(li)
    })
}
getData()

注意:tsc index.ts可能会报错,直接执行 tsc命令编译就行

错误原因是,tsc 编译单个文件会使用默认的tsconfig.json的配置,而且编译单个文件无法指定配置文件

tsconfig.json

// 生成`tsconfig.json`文件  // tsc --init  // tsc -init
{
  "compilerOptions": {
//    "incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
//    "tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
//    "diagnostics": false, // 打印诊断信息
    "target": "ES5", // 目标语言的版本
    "module": "ES2015", // 生成代码的模板标准
//    "outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
    "lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost, 如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
//    "allowJs": true, // 允许编译器编译JS,JSX文件
    "checkJs": false, // 不允许在JS文件中报错,通常与allowJS一起使用
    "outDir": "./dist", // 指定输出目录
    "rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
//    "declaration": false, // 生成声明文件,开启后会自动生成声明文件
//    "declarationDir": "./file", // 指定生成声明文件存放目录
//    "emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
//    "sourceMap": true, // 生成目标文件的sourceMap文件
//    "inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
//    "declarationMap": true, // 为声明文件生成sourceMap
    "typeRoots": [], // 声明文件目录,默认时node_modules/@types
    "types": [], // 加载的声明文件包
    "removeComments":true, // 删除注释
//    "noEmit": false, // 不输出文件,即编译后不会生成任何js文件
//    "noEmitOnError": true, // 发送错误时不输出任何文件
//    "noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
//    "importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
//    "downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
    "strict": true, // 开启所有严格的类型检查
    "alwaysStrict": true, // 在代码中注入'use strict'
    "noImplicitAny": true, // 不允许隐式的any类型
    "strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
    "strictFunctionTypes": true, // 不允许函数参数双向协变
    "strictPropertyInitialization": true, // 类的实例属性必须初始化
    "strictBindCallApply": true, // 严格的bind/call/apply检查
    "noImplicitThis": true, // 不允许this有隐式的any类型
    "noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
    "noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
    "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
    "noImplicitReturns": true, //每个分支都会有返回值
    "esModuleInterop": true, // 允许export=导出,由import from 导入
    "allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
    "moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
    "baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
    "paths": { // 路径映射,相对于baseUrl
      // 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
      "jquery": ["node_modules/jquery/dist/jquery.min.js"]
    },
    "rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
//    "listEmittedFiles": true, // 打印输出文件
//    "listFiles": true // 打印编译的文件(包括引用的声明文件)
  },
  // 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
  "include": [
  ],
  // 指定一个排除列表(include的反向操作)
  "exclude": [
  ],
  // 指定哪些文件使用该配置(属于手动一个个指定文件)
  "files": [
    "index.ts"
  ]
}

常见的配置

{
  "compilerOptions": {
    "target": "ES5", // 目标语言的版本
    "module": "AMD", // 生成代码的模板标准
    "lib": ["DOM", "ES2015"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost, 如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
    "allowJs": true, // 允许编译器编译JS,JSX文件
    "checkJs": true, // 不允许在JS文件中报错,通常与allowJS一起使用
    "outDir": "./dist", // 指定输出目录
    "outFile": "./dist/app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
    "removeComments":false, // 删除注释
    "strict": true, // 开启所有严格的类型检查
    "noImplicitAny": true, // 不允许隐式的any类型
    "strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
    "noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
    "noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
  },
  // 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
  "include": [
    "./*",
  ],
  // 指定一个排除列表(include的反向操作)
  "exclude": [
  ],
}

d.ts声明文件

在引入一些年久的js文件的时候,会存在编辑器不提示或报错的情况

主要原因是这些库是js编写的,开发者并没有编写为ts支持的声明文件

可以尝试输入

npm i @types/包名 -D

安装某个库的声明文件

这是一段express的一段代码,我们尝试在ts的环境下运行

// npm i -D express
import express from "express"
const app = express()
const router = express.Router()
app.use("/", router)
router.get("/", (req, res) => {
    res.json({msg: "hi fengfeng",code: 200})
})
app.listen(9000, () => {
    console.log("server: http://127.0.0.1:9000")
})

自己编写声明文件

import axios from "axios";
import express from "express"
const app = express()
const router = express.Router()
app.use("/", router)
router.get("/", (req: any, res: any) => {
    res.json({code: 200})
})
app.listen(9000, () => {
    console.log("running: :9000")
})

发现报错,且没有提示

ts学习笔记_第1张图片

在项目根目录下创建一个typings/目录

在目录下创建express.d.ts的声明文件

declare module "express" {
    interface Router {
        get(path: string, cb:(req:any, res:any)=>void):void
    }
    interface App {
        use(path: string, router: any): void
        listen(port: number, cb?:()=>void)
    }
    interface Express {
        (): App
        Router(): Router,
    }
    const express: Express
    export default express;
}

construct

构造函数

class People {
    name: string
    constructor(name: string) {
        // this表示当前对象
        this.name = name 
    }
    getName() {
        console.log(this.name)
    }
}
let p: People = new People("枫枫")
console.log(p.name) // 访问属性
p.getName() // 调用方法

public private protected

  • public:类的所有成员都可以被类的实例获取(默认)

  • private:类成员只能在当前类中被访问

  • protected:类成员在类以及子类中可以被访问

class Man {
    private mName: string
    protected mAge: number
    constructor(name: string, age: number) {
        this.mName = name
        this.mAge = age
    }
    getMName(){
        console.log(this.mName) // private  只能在当前类中访问
    }
}
class People extends Man {
    name: string
    private age: number
    constructor(name: string, age: number = 18) {
        super(name, age) // 调用父类的构造方法
        this.name = name
        this.age = age
    }
    getName() {
        console.log(this.mAge) // protected 类的子类可以访问
        console.log(this.name)
    }
}
let p: People = new People("枫枫")
console.log(p.name)
console.log(p.age) // 不能在外面访问

static

只能通过类去调用

class People {
    static ClassName:string = "类名"
    nickName: string
    constructor(nickName: string) {
        this.nickName = nickName
    }
    static getName() {
        console.log(People.ClassName)
    }
}
let p: People = new People("枫枫")
People.getName()

注意

public和上面三个关键字可以连用

static作用于属性上,可以被称为静态属性,类属性

static作用于方法上,可以被称为静态方法,类方法

class People {
    private static ClassName:string = "类名"
    nickName: string
    constructor(nickName: string) {
        this.nickName = nickName
    }
    static getName() {
        console.log(People.ClassName)
    }
}
let p: People = new People("枫枫")
People.getName()
console.log(People)

接口类

注意,interface只能定义公共属性和方法

interface PersonType {
    name: string
    age: number
    getName():string
}
class Person implements PersonType{
    name: string
    age: number
    constructor(name: string, age: number) {
        this.name = name
        this.age = age
    }
    getName(): string {
        return this.name
    }
}
let p1 = new Person("枫枫", 12)

装饰器

装饰器是 ES7 提出的实验性功能

开启装饰器

"experimentalDecorators": true,
"emitDecoratorMetadata": true,

类装饰器 ClassDecorator

装饰器作用,在不改变原有代码的前提下,实现在原有逻辑的前后增加功能

const dr: ClassDecorator = (fn) => {
    // fn就是Animal的构造函数
    console.log(fn)
    // 可以给对象挂载属性和方法
    fn.prototype.myName = "枫枫"
    fn.prototype.getMyName = function () {
        console.log(fn.prototype.myName)
    }
}
@dr
class Animal {
}
let an = new Animal()
console.log((an as any).myName);
(an as any).getMyName()

原理

const dr: ClassDecorator = (fn) => {
    // fn就是Animal的构造函数
    console.log(fn)
    // 可以给对象挂载属性和方法
    fn.prototype.myName = "枫枫"
    fn.prototype.getMyName = function () {
        console.log(fn.prototype.myName)
    }
}
class Animal {
}
dr(Animal)
let an = new Animal()
console.log((an as any).myName);
(an as any).getMyName()

装饰器工厂

使用函数柯里化

const big =  (name: string):ClassDecorator=>{
    return (fn)=>{
        fn.prototype.myName = name
        fn.prototype.getMyName = function () {
            console.log(fn.prototype.myName)
        }
    }
}
@big("zhangsan")
class Animal {
}
let an = new Animal()
console.log((an as any).myName);
(an as any).getMyName()

方法装饰器 MethodDecorator

const get: MethodDecorator = (target, propertyKey, descriptor: PropertyDescriptor) => {
    descriptor.value("获取的数据")
}
class Animal {
    @get
    list(data: string) {
        console.log(data)
    }
}
let an = new Animal()
import axios from "axios";
interface VideoInfo {
    id: number
    title: string
    userName:string
    userPic: string
    coverUrl: string
    playUrl: string
    duration: string
}
interface VideoResponse {
    code: number
    message: string
    result: {
        total: number
        list: T[]
    }
}
const get = (url: string): MethodDecorator => {
    return (target, propertyKey, descriptor: PropertyDescriptor) => {
        axios.get(url).then(res=>{
            descriptor.value(res.data)
        })
    }
}
class Student {
    // @get("")
    create() {
    }
    @get("https://api.apiopen.top/api/getHaoKanVideo")
    list(data: VideoResponse) {
        data.result.list.forEach((value, index, array)=>{
            console.log(index, value.id, value.title, value.userName)
        })
    }
}
let s1 = new Student()

你可能感兴趣的:(go,笔记)