一起从零开始学VUE(18)TypeScript

vite搭建vue3+ts+vue-router+scss

两种创建方式
  1. npm init @vitejs/app 这种安装方式包括ts安装,但是确保node.js版本>=10.16.0,否则会出现报错,

解决方法参考博文:https://blog.csdn.net/Sun_Shydeo/article/details/125983070

image-20230207100224561

  1. npm init vite-app <project-name> 需要自己手动配置安装ts
配置typescript
  • 安装ts npm i -g typescript

  • 初始化 tsconfig.json

    npx tsc --init
    
  • 将main.js修改为main.ts,所有引用的地方也需要改为main.ts

  • 页面中的 <script> 修改为 <script lang="ts">

  • 配置tsconfig,json

{
    
    
  "compilerOptions": {
    
    
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "baseUrl": ".",
    "paths": {
    
    
      "@/*":["src/*"],
      "components":["src/components/*"],
    }
  },
}

  • 配置vite.config.ts
import {
    
     defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
    
    
  plugins: [vue()],
  resolve: {
    
    
    alias: {
    
    
      "@": path.resolve(__dirname, "./src"),
    },
  },
});
安装css预处理器
  1. npm i -D sass 下载处理器

  2. 由于直接在main.ts里导入的话,style标签会访问不到全局Scss中的变量和规则,需要在vite.config.ts中导入全局Scss

import {
    
     defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
// https://vitejs.dev/config/
export default defineConfig({
    
    
  plugins: [vue()],
  resolve: {
    
    
    alias: {
    
    
      "@": path.resolve(__dirname, "./src"),
    },
  },
   // css预处理器
   css: {
    
    
    preprocessorOptions: {
    
    
      scss: {
    
    
        additionalData: `@use "@/styles/index.scss" as *`,
      },
    },
  }
});
安装vue-router
  1. npm i vue-router
  2. 在src下的router目录中新建Index.ts
import {
    
    
    createRouter,
    createWebHistory
  } from 'vue-router'
  
  const routes = [
    {
    
     path: "/", redirect: "/home" },
    {
    
     path: "/home", component: () => import("@/components/HelloWorld.vue") }
  ]
  
  const router = createRouter({
    
    
    history: createWebHistory(process.env.BASE_URL),
    routes
  })
  
  export default router
  1. 在main.ts中挂载router
import {
    
     createApp } from 'vue'
import App from './App.vue'
import router from "@/router";

createApp(App).use(router).mount('#app')

TS的类型

image-20230207113933637

直接使用字面量进行声明(少用)
let b: 'hello' | 'flase';  //b可以是'hello'也可以是'false'
let c: boolean | string; //联合类型  |表示或,&表示与
any表示任意类型(不推荐)

一个变量设置类型为any相当于关闭类型检索,如果变量没有指定类型,则TS解析器会自动判断变量的类型为any(隐式any)

image-20230207115015984

unknown表示未知类型

与any类似,unknown变量可以设置任意类型,与any的区别在于,any类型的变量可以赋值给任意变量,unknown是一个类型安全的any,如果不缩小范围,则无法直接赋值给其他变量,这种机制起到了很强的预防性,更安全,这就要求我们必须缩小类型,我们可以使用typeof类型断言等方式来缩小未知范围(s = e as string 或者 s = < string > e)

let c:unknown;
c =1 ;
c = 'number'

let s:string
c= 'hello'
s = c

image-20230207115317481

函数声明
  1. 常用的结构
function fn():boolean| string{
    
    
  return '111'
}  // 返回布尔类型或者字符串类型
  1. 当函数永远都不会有返回结果时,可以使用never,常用场景:抛出异常
function fn():never{
    
    
  throw new Error('11')
}
  1. 设置函数结构的类型声明 语法:(形参:类型,形参:类型,…)=>返回值
// 正确 
let d :(a1:number,b1:number)=>number
 d = function(a,b){
    
    
  return a+b
 }
// 报错
 let d :(a1:number,b1:number)=>number
 d = function(a:string,b:string){
    
    
  return a+b
 }
  1. 可选参数,在参数名后添加?表示参数是可选的,但是注意可选参数后面不允许再出现必填参数
function buildName(firstName: string, lastName?: string) {
    
    
    if (lastName) {
    
    
        return firstName + ' ' + lastName;
    } else {
    
    
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
  1. 剩余参数
function push(array: any[], ...items: any[]) {
    
    
    items.forEach(function(item) {
    
    
        array.push(item);
    });
}
let a = [];
push(a, 1, 2, 3);
object表示一个js对象
  1. {}用来指定对象中可以包含哪些属性,语法:{属性名:属性值,属性名:属性值,…}
  2. 在属性名后面加上一个?表示属性是可选的
let b : {
    
    name : string,age?:number}
b= {
    
    name:'张三'}
  1. [属性名:string] : any 表示任意类型的属性
let c : {
    
    name:string,[propName:string]:any}
c = {
    
    name:'李四',age:18,gender:'male'}
Array数组

对数组的定义有两种方式,同时还可以定义联合类型或者指定对象成员的数组

 //两种声明方式
 let e :string[]
 let f : Array<number>
 // 定义联合类型数组
 let g :(number | string)[]
 // 定义指定对象成员数组
 interface arrobj{
    
    
	name:string,
    age:number
 }
 let h:arrobj[] = [{
    
    name:'张三',age:23}]
tuple元组
  1. 元组用于保存固定长度固定数据类型的数据,可以限制数组元素的个数和类型。元组支持解构赋值
// 语法:[类型,类型]
let g:[string,string]
 g = ['hello','e']
  1. 可选元素,元组支持来声明元组类型可选的参数,语法:[类型,类型?]
  2. 剩余元素,元组的最后一个元素可以是剩余元素,格式为...X剩余元素代表元组类型是开放的,可以有零个或多个额外的元素。
// 表示带有一个 number 元素和任意数量string 类型元素的元组类型
[number, ...string[]]
enum枚举:列举所有可能情况
 enum Gender{
    
    
  male=0,
  female=1
 }
 let i :{
    
    name:string,gender:Gender}
 i ={
    
    
  name:'王五',
  gender:Gender.male
 }
never:永不存在的值
  1. 如果一个函数执行时抛出了异常,那么这个函数永远不存在返回值(因为抛出异常会直接中断程序运行,这使得程序运行不到返回值那一步,即具有不可达的终点,也就永不存在返回了);

  2. 函数中执行无限循环的代码(死循环),使得程序永远无法运行到函数返回值那一步,永不存在返回

  3. 没有类型是never的子类型或可以赋值给never类型(除了never本身之外),即使any也不可以赋值给never

  4. 使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码。

类型的别名
 type myType = 1|2|3|4
 let k :myType
 let h :myType
非空断言

一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。即x! 将从 x 值域中排除 null 和 undefined 。

注意

null和undefined

默认情况下Null和undefined是所有类型的子类型,可以把null和undefined赋值给其他类型。但如果在tsconfig.json中指定了"strictNullChecks":true ,null 和 undefined 只能赋值给 void 和它们各自的类型。

number和bigint

虽然都表示数字,但是两个类型并不兼容,会抛出一个ts(2322)错误。

object、Object 和 {}

  1. 小 object 代表的是所有非原始类型,也就是说我们不能把 number、string、boolean、symbol等 原始类型赋值给 object。在严格模式下,null 和 undefined 类型也不能赋给 object。
  2. 大Object 代表所有拥有 toString、hasOwnProperty 方法的类型,所以所有原始类型、非原始类型都可以赋给 Object。同样,在严格模式下,null 和 undefined 类型也不能赋给 Object。
  3. {}空对象类型和大 Object 一样,也是表示原始类型和非原始类型的集合,并且在严格模式下,null 和 undefined 也不能赋给 {}

面向对象

对象中主要包含了两个部分(属性和方法),直接定义的属性是实例属性,需要通过对象的实例去访问,使用static开头的属性是静态属性(类属性)可以直接访问,readonly表示只读属性,方法和属性类似

<template>
  <div class="">实例属性:{
   
   { person }}</div>
  <div class="">静态属性:{
   
   { Person.age }}</div>
</template>

<script setup lang="ts">
import {} from "vue";
class Person{
  // 实例属性
  name:string = '孙悟空';
  //在属性前使用static 关键字可以定义类属性
  static age:number = 18;

}
const person = new Person()

</script>

image-20230207142632674

构造函数

class Dog{
    
    
  name:string;
  age:number;
    // 构造函数会在对象创建时调用
  constructor(name:string,age:number){
    
    
      // this表示当前对象
    this.name = name,
    this.age =age
  }
}
const dog1= new Dog("狗1",1)
const dog2 = new Dog("狗2",2)
console.log(dog1,dog2);

继承

关键字:extends

使用继承之后,子类将会拥有父类所有的方法和属性,通过继承可以将多个类中共有的代码写在一个父类中,这样只需要写一次就可以让所有的子类都同事拥有父类的属性,如果在子类中添加了与父类重名的方法,则会重写父类对应的方法。

示例:

class Animals {
    
    
  name: string;
  age: number;
  constructor(name: string, age: number) {
    
    
    (this.name = name), (this.age = age);
  }
  sayHello() {
    
    
    console.log("动物在叫");
  }
}
class Dog extends Animals {
    
    
  sayHello() {
    
    
    console.log(this.name,"旺旺");
  }
}
class Cat extends Animals {
    
    
  sayHello() {
    
    
    console.log(this.name,"喵喵",);
  }
}
const dog1 = new Dog("小狗", 1);
const cat = new Cat("奶牛", 2);
dog1.sayHello();
cat.sayHello();

关键字:super

在类的方法中super表示当前类的父类(超类),如果子类中写了构造函数,则子类构造函数中必须对父类的构造函数进行调用

示例:

class Animals {
    
    
  name: string;
  age: number;
  constructor(name: string, age: number) {
    
    
    (this.name = name), (this.age = age);
  }
  sayHello() {
    
    
    console.log("动物在叫");
  }
}
class Dog extends Animals {
    
    
  fur:string;
  constructor(name:string,age:number,fur:string){
    
    
      //调用父类的构造函数
    super(name,age)  
    this.fur = fur
  }
  sayHello() {
    
    
    console.log(`${
      
      this.name}是一只${
      
      this.fur}的狗,它${
      
      this.age}岁了`);
  }
}
class Cat extends Animals {
    
    
  sayHello() {
    
    
    console.log(this.name,"喵喵",);
  }
}
const dog1 = new Dog("小狗", 1,'黑色');
const cat = new Cat("奶牛", 2);
dog1.sayHello();
cat.sayHello();

抽象类

关键字:abstract,extends

抽象类无法创建对象,可以被继承,抽象类中可以添加抽象方法,抽象方法没有方法体

abstract class Animal{
    
    
  name:string;
  constructor(name:string){
    
    
    this.name = name
  }
  abstract sayHello():void;
}

class Dog extends Animal{
    
    
  sayHello(){
    
    
    console.log(this.name,'汪汪汪')
  }
}
new Dog('小狗').sayHello()

接口

关键字:interface,implements

接口用来定义一个类结构,在定义类时,限制类的结构,接口中的所有的属性都不能有实际的值,在接口中的所有方法都是抽象方法。

属性的封装

上述所讲的属性是在对象中设置的,属性可以任意的被修改,会导致对象中的数据变得非常不安全,通过在属性前面添加属性的修饰符可以限制属性的访问。

  • private 表示私有属性,只能在类内部进行访问和修改,可以通过类中的方法来访问私有属性

  • public修饰的属性可以在任意位置访问,默认

  • protected受保护的属性,只能在当前类和当前类的子类中访问

  • 属性存取器:getter()和setter() 在ts中可以直接写get name(){}

class Dog{
    
    
  // private表示私有属性,只有在类中访问
  private age:number;
  public name : string;
  constructor(name:string,age:number){
    
    
    this.name = name
    this.age = age
  }
  get ages(){
    
    
    return this.age
  }
  set ages(value :number){
    
    
    this.age = value
  }
}
const dog = new Dog("小狗",1)
console.log(dog.ages);

泛型

在定义函数或者类时,如果遇到类型不明确时可以使用泛型

// 单个
function fn<T>(a:T):T{
    
    
  return a;
}
// 多个
function fn<T,K>(a:T,b:K):T{
    
    
  console.log(b);
  return a;
}
// 泛型继承接口或者类
interface Inter{
    
    
  length:number;
}
function fn<T extends Inter,K>(a:T,b:K):T{
    
    
  console.log(b);
  return a;
}
  1. 可以直接调用据有泛型的函数
fn(10); //不指定泛型,ts可以自动对类型进行推断
fn<string>('hello');//指定泛型
  1. 泛型工具类型:
    • typeof在类型上下文中获取变量或者属性的类型
    • keyof获取某种类型的所有键,其返回类型是联合类型
    • in用来遍历枚举类型
    • infer声明一个类型变量并对它进行使用,用它取到函数返回值的类型方便之后使用。

相关链接

vite 安装配置ts遇到的常见问题
Vue3+Ts实现贪吃蛇小游戏

猜你喜欢

转载自blog.csdn.net/qq_46258819/article/details/128920406