vue3+typescript【10】

官网
typescriptlang.org

ts环境配置

TypeScript的编译环境
–安装命令
npm install typescript -g
–查看版本
tsc --version

TypeScript的运行环境

  • 第一步:通过tsc编译TypeScript到JavaScript代码;
    tsc 文件名
  • 第二步:在浏览器或者Node环境下运行JavaScript代码;

化简步骤:

  • 方式一:通过webpack,配置本地的TypeScript编译环境和开启一个本地服务,可以直接运行在浏览器上;
    项目目录结构

    │  index.html
    ├─build
    │      webpack.config.js
    └─src
        main.ts
    
    • 使用npm来初始化package.json文件
      npm init -y

    • 本地依赖TypeScript:为什么需要本地依赖TypeScript

      • 因为我们之后是通过webpack进行编译我们的TypeScript代码的,并不是通过tsc来完成的。(tsc使用的是全局安装的TypeScript依赖)
      • 那么webpack会在本地去查找TypeScript的依赖,所以我们是需要本地依赖TypeScript的;
        npm install typescript
    • 初始化tsconfig.json文件
      tsc --init

    • 配置tslint来约束代码
      npm install tslint -g
      检测代码规范,在项目中初始化tslint的配置文件:tslint.json
      tslint --init

    • 项目环境的Webpack

      • 安装webpack相关的依赖(本地安装)
        npm install webpack webpack-cli webpack-dev-server -D
      • 在package.json中添加启动命令
      "scripts": {
          "test": "echo \"Error: no test specified\" && exit 1",
          "serve": "cross-env NODE_ENV=development webpack-dev-server --mode=development --config build/webpack.config.js"
          },
      
      • 添加webpack的其他相关依赖
        • 依赖一:cross-env: 这个插件的作用是可以在webpack.config.js中通过 process.env.NODE_ENV 来获取当前是开发还是生产环境
          npm install cross-env -D
        • 依赖二:ts-loader: 需要解析.ts文件,所以需要依赖对应的loader:ts-loader
          npm install ts-loader -D
        • html-webpack-plugin: 编译后的代码需要对应的html模块作为它的运行环境,所以我们需要使用html-webpack-plugin来将它插入到对应的模板中
          npm install html-webpack-plugin -D
      • 配置webpack.config.js文件
          const HtmlWebpackPlugin = require("html-webpack-plugin");
      
          module.exports = {
          entry: "./src/main.ts",
          output: {
              filename: "build.js"
          },
          resolve: {
              extensions: [".tsx", ".ts", ".js"]
          },
          module: {
              rules: [
              {
                  test: /\.tsx?$/,
                  use: "ts-loader",
                  exclude: /node_modules/
              }
              ]
          },
          devtool: process.env.NODE_ENV === "production" ? false : "inline-source-map",
          devServer: {
              contentBase: "./dist",
              stats: "errors-only",
              compress: false,
              host: "localhost",
              port: 8080
          },
          plugins: [
              new HtmlWebpackPlugin({
              template: "./index.html"
              })
          ]
          };
      
  • 方式二:通过ts-node库,为TypeScript的运行提供执行环境

    • 安装ts-node
      npm install ts-node -g
    • 另外ts-node需要依赖 tslib 和 @types/node 两个包:
      npm install tslib @types/node -g
    • 现在,我们可以直接通过 ts-node 来运行TypeScript的代码:
      ts-node 文件名

编译ts代码为js代码时,如果出现同名变量会报错,可以通过以下代码解决
export {} //直接赋值粘贴,内部不用写内容

变量的声明

var/let/const 标识符: 数据类型 = 赋值;
类型注解就是指数据类型
在tslint中并不推荐使用var来声明变量:主要原因和ES6升级后let和var的区别是一样的,var是没块级作用域的,会引起很多的问题

函数返回值注解:默认是为void,们通常情况下不需要返回类型注解,因为TypeScript会根据 return 返回值推断函数的返回类型

let foo = 'foo' 此时的foo为string类型
默认情况下进行赋值时,会将赋值的值的类型,作为前面标识符的类型
这个过程叫做类型推导/推断

string是TypeScript中的字符串类型
String是JavaScript的字符串包装类的类型

JavaScript和TypeScript的数据类型

Js数据类型
  • JavaScript类型:
    number、boolean、string、Array、Object、Symbol、null和undefined
    • 数组类型的定义:

      const names: string[] = ["a", "b"]
      const names2: Array<string> = ["a", "b"]

    • 对象类型:

          const myInfo: Object = {
              name: "hahah",
              age:18
          }
      

      从myinfo中我们不能获取数据,也不能设置数据
      myInfo["name"] = "lalala"
      console.log(myInfo["age"])
      console.log(myInfo.age)都会报错

    • Symbol类型:
      可以通过symbol来定义相同的名称,因为Symbol函数返回的是不同的值

          const s1: symbol = Symbol("title")
          const s2: symbol = Symbol("title")
          const person = {
              [s1]: "hahaha",
              [s2]: "lalala"
          }
      
ts数据类型
  • TypeScript类型
    any、unknown、void、never、tuple

    • any类型:
      无法确定一个变量的类型,并且可能它会发生一些变化,这个时候我们可以使用any类型

      let a: any = "lalala"
      a = 123; //不报错
      
    • unknown类型:
      用于描述类型不确定的变量,一般用于不知道函数返回值类型

    let result: unknown
    result = foo()
    

    unknown类型和any类型的区别:unknown类型只能赋值给any和unknown类型,any类型可以赋值给任意类型

    • never类型
      never 表示永远不会发生值的类型,比如一个函数是一个死循环或者抛出一个异常,那么这个函数不会返回东西

    • tuple类型

      • 数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。(可以放在对象或者元组中)
        const tuple:[T, newState: ()=> void]
        其中()=>void表示函数类型 ,一般有以下两种写法:
      1. const foo: ()=>void = ()=>{}
      2.  type MyFunction = ()=>void
         const foo: MyFunction = ()=>{}
        
      • tuple通常可以作为函数返回的值
          return [currentState, changeState]
      
对象类型
  • 属性之间可以使用 , 或者 ; 来分割,最后一个分隔符是可选的
  • 每个属性的类型部分也是可选的,如果不指定,那么就是any类型
  • **可选类型:**对象类型也可以指定哪些属性是可选的,可以在属性的后面添加一个?
    function Print(point: {x: number, y: number, z?:number}){...} ----- 其实上,可选类型可以看做是 类型 和 undefined 的联合类型 函数的可选类型需要在必传参数的后面
联合类型
  • 联合类型是由两个或者多个其他类型组成的类型
  • 表示可以是这些类型中的任何一个值
  • 缩小联合:TypeScript可以根据我们缩小的代码结构,推断出更加具体的类型
        function print(id: number | string){
            if(typeof id === 'string'){
                console.log("你的id是:", id.toUpperCase());
            }else{
                console.log("你的id是:", id)
            }
        }
    

类型别名:对于联合类型对象类型,可以起一个别名来实现多次使用。

//对象类型
type Point = {
    x: number,
    y: number
}
function print(point: Point){
    console.log(point.x, point.y);
}
//联合类型
type ID = number | string
function print(id: ID){
    console.log(id);
}
枚举类型

枚举允许开发者定义一组命名常量,常量可以是数字、字符串类型。一般字符都是大写。
枚举类型默认是有值的,默认值是从0开始的整数类型

enum Direction{
    LEFT,
    RIGHT,
    TOP,
    BOTTOM
}
function turnDirection(direction: Direction){
    switch(direction){
        case Direction.LEFT:
            console("...left")
            break;
        case Direction.RIGHT:
            ...
    }
}
泛型

参数类型不确定的时候可以使用泛型,即将类型参数化
泛型使用的两种方式:

  • 方式一:通过 <类型> 的方式将类型传递给函数;
function foo<Type>(arg: Type): Type{
    return arg
}
  • 方式二:通过类型推到,自动推导出我们传入变量的类型
foo("abc")
//推导出来的主要是字面量类型
  • 当传入多个类型时:
    function foo<T, E>(a1: T, a2: E) {}
    
    • 平时在开发中我们可能会看到一些常用的名称:
      • T:Type的缩写,类型
      • K、V:key和value的缩写,键值对
      • E:Element的缩写,元素
      • O:Object的缩写,对象
        不仅函数可以使用泛型,还可以编写泛型接口和泛型类。
        泛型约束
        举个栗子:只要是拥有length的属性都可以作为我们的参数类型
interface ILength {
    length: number
}
function getLength<T extends ILength>(args:T) {
    return args.length
}
console.log(getLength("abc"))
console.log(getLength(["abc", "cba"]))
console.log(getLength({length: 100, name:"why"}))
类型断言as

TypeScript只允许类型断言转换为 更具体 或者 不太具体(any/unknown) 的类型版本,此规则可防止不可能的强制转换

const el = document.getElementById('my-img') as HTMLImageElement
el.src = "url地址"
非空类型断言

非空断言使用的是!,表示可以确定某个标识符是有值的,跳过ts在编译阶段对它的检测

function print(message?: string){
    console.log(message!.toUpperCase()))
    //由于可选类型,为传入的message有可能是为undefined的,这个时候是不能执行方法的。但是,我们确定传入的参数是有值的,这个时候我们可以使用非空类型断言。
}
可选链的使用

可选链事实上并不是TypeScript独有的特性,它是ES11(ES2020)中增加的特性

  • 可选链使用可选链操作符 ?.
  • 它的作用是当对象的属性不存在时,会短路,直接返回undefined,如果存在,那么才会继续执行
    console.log(info.friend?.girlFriend?.name);

空值合并操作符??)是一个逻辑操作符,当操作符的左侧是 null 或者 undefined 时,返回其右侧操作数,否则返回左侧操作数

可选链不能用于赋值。

字面量类型

let message = "hello" message为string类型
const message = "hello" message为: "hello"类型
字符串本身也可以作为类型,叫做字面量类型
字面量类型的意义就是必须结合联合类型,从普通的数据类型到可以使用字符串作为类型。

type Alignment = 'left' | 'right' |'center'
let align: Alignment = 'left'
align = 'right'
align = 'center'

const 不可以随意修改值,除非是对象类型(引用)

字面量赋值:TypeScript在字面量直接赋值的过程中,为了进行类型推导会进行严格的类型限制,但是如果我们是将一个 变量标识符 赋值给其他的变量时,会进行freshness擦除操作。

interface IPerson{
    name:string,
    eating: ()=>void
}
const obj = {
    name: "why",
    age:18,
    eating: function(){

    }
}
const p: IPerson = obj;
//如果直接将obj的对象赋值给p会报错

类型缩小

typeof

检查返回的值typeof是一种类型保护

        function print(id: number | string){
            if(typeof id === 'string'){
                console.log("你的id是:", id.toUpperCase());
            }else{
                console.log("你的id是:", id)
            }
        }
平等缩小(=、!

可以使用Switch或者相等的一些运算符来表达相等性(比如===, !==, ==, and != )

type Direction = 'left' | 'right' | 'center'
function turnDirection(direction: Direction){
    switch (direction) {
        case 'left':
            console.log("...left");
            break;
        case 'right':
            console.log("...right");
            break;
        case 'center':
            console.log("...center");
            break;
        default:
            console.log("...default");
    }
}
instanceof

JavaScript 有一个运算符来检查一个值是否是另一个值的实例

function print(date: Date | string){
    if(date instanceof Date){
        console.log(date.toLocaleString);
    }else{
        console.log(date);
    }
}

实例是new的

in

用于确定对象是否具有带名称的属性:in运算符.
如果指定的属性在指定的对象或其原型链中,则in 运算符返回true

type Fish = {swim: ()=>void}
type Dog = {run: ()=>void}
function move(animal: Fish | Dog) {
    if ('swim' in animal){
        animal.swim()
    }else{
        animal.run()
    }
}

这里的animal是一个常量,并非实例.

函数

剩余参数:将一个不定数量的参数放到一个数组中

function sum(...nums: number[]){
    let total = 0
    for(const num of nums){
        total+=num
    }
    return total
}
const result = sum(10,20,30)
console.log(result)
函数重载

一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现
注意,有实现体的函数,是不能直接被调用的

function sum(a1: number, a2:number): number;
function sum(a1: string, a2:string): string;
//没有函数体
function sum(a1: any, a2: any): any {
    return a1+a2
}
console.log(sum(20,30));
console.log(sum("aaa","bbb"));

在可能的情况下,尽量选择使用联合类型来实现

接口

索引类型

interface lang{
    [name: string]: number
}
const langues: lang = {
    "Java": 1995,
    "JavaScript": 1996,
    "C": 1972
}

函数类型

interface Calc{
    (num1: number, num2: number): number
}
const add: Calc = (num1, num2) =>{
    return num1+num2
}

除非特别的情况,还是推荐使用类型别名来定义函数
type Calc = (num1: number, num2: number) => number

interface和type区别

  • 如果是定义非对象类型,通常推荐使用type
  • interface 可以重复的对某个接口来定义属性和方法;
    • 如果接口重名,会叠加接口内容
  • 而type定义的是别名,别名是不能重复的

模块化开发

TypeScript支持两种方式来控制我们的作用域:

  • 模块化:每个文件可以是一个独立的模块,支持ES Module,也支持CommonJS;
  • 命名空间:通过namespace来声明一个命名空间
export namespace Time {
    export function format(time: string){
        return '2022-xx-xx'
    }
}

export namespace Price {
    export function format(price: number) {
        return 'xxxx.xx'
    }
}

类型查找

.d.ts 文件,它是用来做类型的声明(declare)。它仅仅用来做类型检测,告知typescript我们有哪些类型
typescript会在以下三个地方查找类型声明

  • 内置类型声明;
    在安装typescript的环境中会带有的

  • 外部定义类型声明;
    方式一:在自己库中进行类型声明(编写.d.ts文件),比如axios
    方式二:通过社区的一个公有库DefinitelyTyped存放类型声明文件

    • 该库的GitHub地址:https://github.com/DefinitelyTyped/DefinitelyTyped/
    • 该库查找声明安装方式的地址:https://www.typescriptlang.org/dt/search?search=
    • 比如安装react的类型声明: npm i @types/react --save-dev
  • 自己定义类型声明;
    以下情况需要自己定义声明文件:

    • 情况一:我们使用的第三方库是一个纯的JavaScript库,没有对应的声明文件;比如lodash
    • 情况二:我们给自己的代码中声明一些类型,方便在其他地方直接进行使用
      声明模块的语法: declare module '模块名' {}
      在声明模块的内部,我们可以通过 export 导出对应库的类、函数等
        declare module "lodash" {
            export function join(args: any[]): any;
        }
    
declare文件

在开发vue的过程中,默认是不识别我们的.vue文件的,那么我们就需要对其进行文件的声明

declare module '*.vue' {
    import { DefineComponent} from 'vue'
    const component: DefineComponent

    export default component
}

如在开发中我们使用了 jpg 这类图片文件,默认typescript也是不支持的,也需要对其进行声明

declare module '*.jpg' {
    const src: string
    export default src
}

ajax的使用:

  1. 引入jQuery
    CDN地址: https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js
  2. 命名空间声明
declare namespace $ {
    function ajax(setting: any): void
}
  1. 使用
$.ajax({
    url: "http://123.207.32.32:8000/home/multidata",
    success: (res: any) => {
        console.log(res);
    }
})
tsconfig.json文件
"compilerOptions": {
  "incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
  "tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
  "diagnostics": true, // 打印诊断信息 
  "target": "ES5", // 目标语言的版本
  "module": "CommonJS", // 生成代码的模板标准
  "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": true, // 允许在JS文件中报错,通常与allowJS一起使用
  "outDir": "./dist", // 指定输出目录
  "rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
  "declaration": true, // 生成声明文件,开启后会自动生成声明文件
  "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": true, // 不输出文件,即编译后不会生成任何js文件
  "noEmitOnError": true, // 发送错误时不输出任何文件
  "noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
  "importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
  "downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
  "strict": true, // 开启所有严格的类型检查
  "jsx": "preserve", // 指定 jsx 格式
  "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// 打印编译的文件(包括引用的声明文件)
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3 + TypeScript 是一种常用的前端开发技术组合,它结合了Vue框架的便捷性和TypeScript的类型检查能力,可以提高项目的可维护性和开发效率。下面是一些Vue3 + TypeScript项目经验的介绍: 1. 项目初始化:使用Vue CLI创建一个Vue3项目,并选择TypeScript作为项目的语言。这样可以自动生成一些基本的配置和文件结构,方便快速开始开发。 2. 类型定义:在Vue3 + TypeScript项目中,可以使用TypeScript的类型系统来定义组件的props、data、computed等属性的类型,以及事件的参数类型等。这样可以在编码过程中及早发现潜在的类型错误,提高代码的健壮性。 3. 组件开发:在Vue3 + TypeScript项目中,可以使用装饰器(decorators)来定义组件选项,例如使用@Prop来定义props属性的类型,使用@Emit来定义事件的参数类型。这样可以更清晰地描述组件的接口和行为。 4. 路由管理:在Vue3 + TypeScript项目中,可以使用Vue Router进行路由管理。通过定义路由的类型和参数类型,可以在编码过程中获得更好的类型提示和错误检查。 5. 状态管理:在Vue3 + TypeScript项目中,可以使用Vuex进行状态管理。通过定义状态的类型和操作的参数类型,可以提高代码的可读性和可维护性。 6. 第三方库的使用:在Vue3 + TypeScript项目中,可以使用第三方库,并为其编写类型声明文件,以获得更好的类型检查和代码提示。例如,可以使用axios发送HTTP请求,并为其编写类型声明文件,以确保请求参数和响应数据的类型正确。 7. 单元测试:在Vue3 + TypeScript项目中,可以使用Jest等测试框架进行单元测试。通过编写类型安全的测试用例,可以提高代码的质量和可靠性。 8. 构建和部署:在Vue3 + TypeScript项目中,可以使用Webpack等构建工具进行项目的打包和优化。通过配置合适的TypeScript编译选项和Webpack插件,可以生成高效的生产环境代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值