将vue+js项目改造成vue+typescript

1,339 阅读4分钟

官方手册

为什么要使用typescript

优点

  1. 程序更容易理解
    • javascript:函数输入输出的参数类型,外部条件等,需要手动调试
    • typescript:已解决此问题
  2. 效率更高
    • 在不同代码块和定义中进行跳转 (IDE和complier)
    • 代码自动补全
    • 丰富的接口提示
  3. 更少的错误
    • 编译期间能够发现大部分错误
    • 杜绝一些常见的错误 (在编译的时候进行判断)
  4. 非常好的包容性
    • 完全兼容javascript
    • 第三方库可以单独编写类型文件
    • 流行项目都支持Typescript (React/Vue/Angular/Ant design)等

缺点

  1. 增加了一些学习成本
  2. 短期内增加了开发成本,对大项目长期来看是节省了时间

tsc:typescript complier // ts编译器

ts只用于静态检查,如果有错误,编译的时候就会报错

基础类型

javascript 8种数据类型

  • 7种原始类型
    • Boolean
    • Null
    • undefined
    • Number
    • String
    • BigInt (es6加的原始类型)
    • Symbol(es6加的原始类型)
  • 和Object

相关问题

  1. null 和 undefined 区别
    • null 和 undefined 是 ts 中的基础类型, null 和 undefined 是所有类型的子类型,可以赋值给任意类型let num: number = undefined不会报错
    • 如果设置了strictNullChecks: true 时,就不能将 null 和 undefined 赋值给除 void 外的其他类型 www.cnblogs.com/wjaaron/p/1…
  2. any和联合类型区别
    • 有明确类型时,避免使用any,会丧失类型检查的作用,这时可用联合类型
    • 联合类型: let numberOrString: number | string = 22
  3. array和tuple 数组和元组
    • 数组:与 js 数组基本相同
      const arr: number[] = [1,2,3];
      const stringArr: string[] = ['a', 'b', 'c'];
      // 如果这个数组里面既存数字又存字符串, 如何写
      const arr1: (number | string)[] = [1, '2' ,3];
      
      // 除了基本类型的数组,对象类型的数组怎么写
      const objectArr: {name: string, age: number}[] = [{name:'a', age:16}]
      // 将上面的写法简化下,利用 type alias 类型别名
      type User = {name: string, age: number}
      const objectArr1: User[] = [{name:'a', age:16}]
      
    • 元组: 数量确定,类型确定
        const teacherinfo1: (string | number)[] = ['zina', 'girl', 18];
      

泛型 generics

适配灵活的类型

为什么使用泛型

function echo(arg: number): number {
    return arg
}
const result = echo(123)

function echo(arg: string): string {
    return arg
}
const result = echo('aaa')

上面,想要的是,传入和返回值类型统一,用any则丢失了类型

解决方案

function echo<T>(arg: T): T { 
    return arg
}

泛型交换元组的顺序

function swap<T, U>(tuple: [T, U]): [U: T] {
    return [tuple[1], tuple[0]]
}
const result = swap(['aaa', 123])
// 现在能确定result每一项的类型

约束泛型

function loggingIdentity<T>(arg: T): T { 
    console.log(arg.length); // Error: T doesn't have .length 
    return arg;
 }

只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求

定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束

interface Lengthwise {
    length: number;
} 
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length); // Now we know it has a .length property, so no more error return arg;
}
// 现在只要有.length属性的入参,都能调用这个方法

类中使用泛型

接口使用泛型

interface KeyPair<T, U> {
    key: T;
    value: U;
}
let kp1: KeyPair<number, string> = {key: 123, value: 'str'}
let arr: number[] = [1,2,3]
let arrTwo: Array<number> = [1,2,3]

类型别名

主要用于联合类型

type NameResolver = () => string
type NameOrResolver = string | NameResolver
function getName(n: NameOrResolver): string {
    if (typeof n === 'string) {
    }
}

在vue中使用typescript的报错及解决方案

👉Property 'relevantColumns' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, unknown, Readonly<Record<never, any>>>'.

image.png

解决方案:在头部进行声明,如下图

参考stackoverflow解答

image.png

👉Expected 0 arguments, but got 2 or more.

上述进行声明后,下一个报错

image.png

解决方案:声明入参的个数要和真实传参相同

image.png

将声明文件提取出来

参考 blog.csdn.net/weixin_4329…

vue2.0以上,创建.d.ts文件

  • 试过vue2.6.11版本,要写在typings.d.ts文件中才能生效

image.png

import Vue from 'vue'
// 为实例和类添加额外约束
declare module 'vue/types/vue' {	// 在types/vue.d.ts里Vue有构造函数类型
  interface Vue {	// 声明合并,会添加到类的原型上
    $myProperty: string	
  }

  interface VueConstructor { // 声明全局属性,即Vue.$myGlobal
    $myGlobal: string
  }
}

2、vue3.0版本

// 声明往Vue实例上添加的属性
// 方式一: 在main.ts,createApp之前添加
declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    foo:string
  }
}
// 方式二: 在src下创建x.d.ts文件
declare module '@vue/runtime-core' {
  interface ComponentCustomProperties {
    foo:string
  }
}
export {}   // 这里需要export/export default任意内容,暂未知原因