从零开始学typescript

https://coding.imooc.com/learn/list/412.html
公司花钱买的,我边学边做笔记

设置

vscode设置

在这里插入图片描述
然后下个Prettier - Code formatter
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以后保存就能格式化了

下载ts

npm install typescript@3.6.4 -g ts版本
npm install -g ts-node@8.4.1 node执行ts文件
这样,以后就能

//demo.ts
console.log(123);

PS D:\touchFish\code\typeScript> ts-node.cmd .\demo.ts
123

一些类型?

// 基础类型就布兰、字符、数值就不一一列出
// 对象类型
const func1 = (str: string) => {
    return parseInt(str)
}

// 自定义对象类型
interface Person {
    name: string
}

const p: Person = {
    name: 'jack'
}

// 泛型类型?
let temp: number | string = 123;
temp = '456'

然后interface、class、type这3个写法都差不多?不知道区别是啥,不像java分那么细

元组

长度和类型都固定的数组

const tuple: [string, string, number] = ['a', 'b', 1]

interface

interface Person{
    // private 
    readonly name:string;
    // 可有可无的属性
    age?:number;
    // 允许有其他的属性
    [propName:string]:any;    
    // 要有个函数,返回类型为string
    say():string;
}

然后一样像Java,interface可以被interface 继承extends
然后class一样可以implementsinterface
interface一样地,只是写而没有实际地方法内容之类的,要在class中写

class

老Java了

// public 公共
// private 私有
// protected 允许类内和子类使用

class Person {
    public name: string;
    private age: number;
    protected sayHi() {
        this.name; //使用共有
        this.age; //允许类内使用
        console.log('hi');
    }
}

class Teacher extends Person {
    public say() {
        this.sayHi() //允许类内使用
        this.name
        // this.age//私有,读不了
    }
}

const T = new Teacher()
// console.log(T.sayHi());//访问不了,因为sayHi是protected,只允许类内和子类使用


构造器

老Java了

class Person {
    constructor(public name: string) { }
}

class Teacher extends Person {
    constructor(public name: string, public age: number) {
        super(name)
    }
}

const teacher = new Teacher('tom', 12);

get和set

老Java了

static单例模式

老Java了


class Person {
    private constructor(public name: string) { }

    static createObj(name: string) {
        return new Person(name)
    }
}

const p = Person.createObj('啊强')
console.log(p.name);

抽象类

老java了

ts文件使用js类的包

比如在ts中npm install js的包,会导致不识别,这时候可以再进行
npm install @types/xxx -D
这个相当于

ts —> xxx.d.ts (翻译文件,用于ts识别js) --> js

ts的文件配置

tsc --init

生成一个tsconfig.json文件,
顺便说,npm init -y可以生成package.json

很明显嘛,一些json,都是配置项,下面跟着视频用一些简单的配置

tsc

创建个文件,test.ts,


class A {
    name: string
    constructor(name: string) {
        this.name = name
    }
}

const asdasd = new A('aaa')
console.log(asdasd.name);

然后tsc,就会自动编译成js嘛

//test.js
"use strict";
var A = /** @class */ (function () {
    function A(name) {
        this.name = name;
    }
    return A;
}());
var asdasd = new A('aaa');
console.log(asdasd.name);

tsc就是自动将根目录的ts转变为js,
如果多个ts,但只想编译其中某几个,就可以再tsconfig.json中配置

{
  "include":["./test.ts"],
}

热更新

tsc -w

输出为单文件

这里是一个ts生成一个js,但也可以只生成一个js,只要设置

   "outFile": "./dist/page.js",                       /* Concatenate and emit output to single file. */

类型保护方式

class Bird {
    sing: () => {};
}

class Dog {
    bark: () => {};
}

// as 来做保护
function tarin(animal: Bird | Dog) {
    (animal as Bird).sing;
    (animal as Dog).bark;
}

// in来做保护
function tarin2(animal: Bird | Dog) {
    if ('sing' in animal) {
        animal.sing();
    } else {
        animal.bark();
    }
}

class NumberObj {
    count: number;
}

// instanceof来做保护
function add(first: object | NumberObj, second: object | NumberObj) {
    if (first instanceof NumberObj && second instanceof NumberObj) {
        return first.count + second.count;
    }
    return 0;
}

枚举

enum Status{
    OFF,
    ON,
    DELETE
}
console.log(Status);
console.log(Status.OFF);
console.log(Status[0]);

{ ‘0’: ‘OFF’, ‘1’: ‘ON’, ‘2’: ‘DELETE’, OFF: 0, ON: 1, DELETE: 2 }
0
OFF

泛型

function join<T>(first: T, second: T) {
    return `${first}${second}`;
}

const res = join<String>('1', '2')
console.log(res);

12

命名空间namespace

其实就是把类统筹到一起,叫做命名空间namespace
比如

//这有一个命名空间,有2个类
namespace Components {
    export class Header {
        constructor() {
            console.log('I am Header');
        }
    }

    export class Content {
        constructor() {
            console.log('I am Content');
        }
    }
}
//这有另一个命名空间,下面这段话相当于import引入的写法
///<reference path="Components.ts"/>

namespace Home {
    export class Page {
        constructor() {
            new Components.Content();
            new Components.Header();
        }
    }
}

然后我们设置打包

{
  "compilerOptions": {
    /* Basic Options */
    // "incremental": true,                   /* Enable incremental compilation */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "amd",    //只支持amd或者system                 /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "outFile": "./dist/page.js",     //输出单文件                  /* Concatenate and emit output to single file. */
    "outDir": "./dist",       //输出文件                 /* Redirect output structure to the directory. */
    "rootDir": "./src",      //要打包的文件                 /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
    "strict": true,            
    "esModuleInterop": true                  
  }
}

导出来的js

装饰器

这和java的注解很是相似
要先开启tsconfig.json的

{
  "compilerOptions": {
    "experimentalDecorators": true,       
    "emitDecoratorMetadata": true,        
  }
}
function Path(target: any) {
    console.log('我是装饰器');

}

function PathParam(str1: string, str2: string) {
    return function (target: any) {
        console.log(str1 + str2);

    }
}

@Path
class Test { }

@PathParam('hello', 'world')
class Test2 { }

ts-node跑一下

我是装饰器
helloworld

方法的装饰器

// 普通方法:target对应类的prototype,key对应方法名,
// descriptor可以理解为一些设置,比如不可修改值之类的功能
function getNameDecorator(target: any, key: string,descriptor:PropertyDescriptor) {
    console.log(target);
    console.log(key);
}

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

    @getNameDecorator
    getName() {
        return this.name
    }
}

{ getName: [Function (anonymous)] }
getName

不是很懂。。。。

访问器的装饰器

其实也是一个样

// 普通方法:target对应类的prototype,key对应方法名,
// descriptor可以理解为一些设置,比如不可修改值之类的功能
function visitDecorator(target: any, key: string, descriptor: PropertyDescriptor) {
    console.log(target);
    console.log(key);
}

class Test {
    private _name: string;
    constructor(name: string) {
        this._name = name;
    }

    get name() {
        return this._name
    }

    @visitDecorator
    set name(name: string) {
        this._name = name;
    }
}

{}
name

这个descriptor很神奇,有很多东西,具体可以看官网

属性的构造器

属性没有descriptor,要这样写

function visitDecorator(target: any, key: string) {
    const descriptor:PropertyDescriptor = {
        writable:false
    }
    return descriptor
}

参数的构造器

function paramDecorator(target: any, method: string, paramIndex: number) {
    console.log(target);
    console.log(method);
    console.log(paramIndex);
}

class Test {
    getInfo(@paramDecorator name: string, age: number) {
        // console.log(name, age);
    }
}

const test = new Test();
test.getInfo('Dell', 30)

实际应用

比如做一个通用的捕捉异常注解

const userInfo: any = undefined

function catchError(target: any, key: string, descriptor: PropertyDescriptor) {
    // 这里就代表函数里面的所有内容,比如为 reruen userInfo.name
    const fn = descriptor.value;
    descriptor.value = function () {
        try {
            fn();
        } catch (e) {
            console.log('userInfo有问题');
        }
    }
}

class Test {
    @catchError
    getName() {
        return userInfo.name
    }
}

const test = new Test()
test.getName()

userInfo有问题

常见的一些操作

1. 配置统一参数

比如一些vueuse的,都是统一一个options参数,然后要配置的话就写参数进去,无的话就默认配置。js我不知道怎么实现,但ts很容易配置

//这是一个接口,2个参数都是可选的
interface config {
  loading?: boolean
  b?: string
}

//这里,config={}是为了占位符,一般都是在最后面才做的这个
export function test(config: config = {}) {
	//定义常量
  const {
    //如果loading原本有值的话,就取config.loading里面的,否则就默认是true。这种写法对js来说是无的
    loading = true,
    b = '123',
  } = config
  console.log(loading, b)
}

重写类型(interface)

比如在vue router中,

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),

  routes: [{
    path: '/about',
    name: 'about',
    component: () => import('@/views/AboutView.vue'),
    meta:{
    	title:'主页'
    	}
  },]
})

其中的routes类型为 RouteRecordRaw[]
但是其中的meta类型,是RouteMeta

export declare interface RouteMeta extends Record<string | number | symbol, unknown> {
}

可以说这是个泛型,但是我们在项目中,meta不可能是多变化的嘛,最好就是统一meta的字段,方便我们以后使用,上去官网查,发现这样
在这里插入图片描述
这样确实可以实现我们的目标了,明确地定义meta里面是什么样子

//冲定义
declare module 'vue-router' {
  interface RouteMeta {
    title?: string //导航条标题
    showNav?: boolean //是否显示导航条
    rightText?: string //导航条
    rightFunction?: () => void //点击右边文字按钮实现的方法
    closeWevView?: boolean //当前页面返回是否关闭H5页面
    rightIcon?: string //右上角icon
    documentTitle?: string //浏览器标题
  }
}

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'home',
    component: HomeView,
    //这样meta就统一了
    meta: {
      title: '主页',
      showNav: true, //是否显示左上角返回按键
      rightText: '按钮', //右上角按钮文字,如果没有则不显示
      closeWevView: true, //当前页面点返回是否关闭H5页面
      //点击右上角按钮文字触发的方法
      rightFunction: () => {
        console.log('ssss')
      },
      rightIcon: 'chat-o',
    },
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('@/views/AboutView.vue'),
  },
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: routes,
})

断言

就是比如uni.request,在函数写着返回必然是一个string类型,但是我想写成必然是number类型,可以用断言进行强制转换

const numberData = stringData as number
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值