Vue3 + Typescript 从0到1开发通用基础组件
1. 什么是 TypeScript
TypeScript相关手册
https://www.typescriptlang.org/zh/
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
安装 Typescript
shell
$ node -v
v14.19.1
$ npm -v
6.14.16
$ npm install -g typescript
D:\data\nodejs\node_global\tsc -> D:\data\nodejs\node_global\node_modules\typescript\bin\tsc
D:\data\nodejs\node_global\tsserver -> D:\data\nodejs\node_global\node_modules\typescript\bin\tsserver
+ typescript@4.7.4
added 1 package from 1 contributor in 2.251s
$ tsc -v
Version 4.7.4
# 可选补充安装
$ npm install -g ts-node手写一个Demo
- 创建app.ts
typescript
var hello = (name: string) => {
return `hello ${name}`
}
hello('world')- 运行ts编译命令
shell
$ tsc app.ts
$ ls
app.js app.ts
$ cat app.js
var hello = function (name) {
return "hello ".concat(name);
};
hello('world');- 更改保存 app.ts(编译错误的语法)
typescript
var hello = (name: string) => {
return `hello ${name}`
}
hello(123)- 再次运行ts编译命令
shell
$ tsc app.ts
app.ts:5:7 - error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
5 hello(123)
~~~
Found 1 error in app.ts:5此时,依然能正常生成app.js。需要自行排查问题
2. 原始数据类型和 Any 类型
- 创建basic-types.ts
typescript
let isDone: boolean = false
let age: number = 29
let firstName: string = 'lintong'
let message: string = `Hello, ${firstName}`
let u: undefined = undefined
let n: null = null
let notSure: any = 4
notSure = 'maybe a string'
notSure = true
notSure.myName
notSure.getName()3. 数组和元祖
Tuple 元祖:元祖的表示和数组非常类似,只不过它将类型写在了里面 这就对每一项起到了限定的作用
- 创建array-and-tuple.ts
typescript
let arrOfNumbers: number[] = [1, 2, 3]
arrOfNumbers.push(4)
// push除number以外的会报错提示
// arrOfNumbers.push('hello')
function test() {
console.log(arguments) // 类数组
// 以下被允许
let length = arguments.length
let arr0 = arguments[0]
console.log(length, arr0)
// 以下都不被允许
// arguments.forEach
// let arr: any[] = arguments
}
test()
let user: [string, number] = ['lintong', 29]
// 添加string、number类型则正常push
user.push(30)
// 会报错
// user.push(true)4. Interface-接口
对对象的形状(shape)进行描述
Duck Typing(鸭子类型)
- 创建interface-basic.ts
typescript
interface Person {
readonly id: number
name: string
age?: number // ?:可选参数。实例化时不会检测其是否存在该属性
}
let lintong: Person = {
id: 1,
name: 'lintong',
age: 29
}
// lintong.id = 2 // 只读属性,只能被赋值一次,之后不能再被更改5. 函数
在 JS 中,函数是一等公民。
- 创建function-types.ts
typescript
const add = (x: number, y: number, z?: number): number => {
if (typeof z === 'number') {
return x + y + z
}
return x + y
}
let result1 = add(1, 2)
let result2 = add(1, 2, 3)
// let result3 = add(1, '2') // 报错
// let add2: number = add // 报错
let add3: (x: number, y: number, z?: number) => number = add // 正确
// 等同于 add3
interface ISum {
(x: number, y: number, z?: number): number
}
let add4: ISum = add6. 类型推论 联合类型和类型断言
类型推论 - 没有明确的指定类型的时候推测出一个类型
联合类型 - 表示类型或的关系
类型断言 - 类型断言用来告诉编译器你比它更了解这个类型。不是类型转换,断言成一个联合类型中不存在的类型是会出现错误的
类型守卫 - 当遇到一个联合类型的时候,使用条件语句,它可以自动帮你来缩小类型的范围:typeof 和 instanceof 关键字
- 创建type-interface-and-more.ts
typescript
// type interface
let str = 'str'
// str = 123 // 报错
// union types
let numberOrString: number | string
numberOrString = 'abc'
numberOrString = 123
// 访问某一个类型独有的属性会报错
// numberOrString.length // 报错
// 访问共有属性则没问题
numberOrString.toString()
numberOrString.valueOf()
function getLength(input: string | number): number {
const str = input as string
if (str.length) {
return str.length
} else {
const number = input as number
return number.toString().length
}
}
// type guard
// 改写 getLength 函数
function getLength2(input: string | number): number {
if (typeof input === 'string') {
return str.length
} else {
return input.toString().length
}
}7. 枚举(Enum)
- 创建enums.ts
typescript
enum Direction {
Up,
Down,
Left = 10,
Right,
}
console.log(Direction.Up) // 0
console.log(Direction[0]) // Up
console.log(Direction[10]) // Left
console.log(Direction.Right) // 11- 运行ts编译命令
shell
$ tsc enums.ts
$ cat enums.js
var Direction;
(function (Direction) {
Direction[Direction["Up"] = 0] = "Up";
Direction[Direction["Down"] = 1] = "Down";
Direction[Direction["Left"] = 10] = "Left";
Direction[Direction["Right"] = 11] = "Right";
})(Direction || (Direction = {}));
console.log(Direction.Up); // 0
console.log(Direction[0]); // Up
console.log(Direction[10]); // Left
console.log(Direction.Right); // 11- 使用场景1
typescript
enum Direction {
Up = 'UP',
Down = 'Down',
Left = 'Left',
Right = 'Right',
}
const value = 'UP'
if (value === Direction.Up) {
console.log('go up!')
}- 运行ts编译命令
shell
$ tsc enums.ts
$ cat enums.js
var Direction;
(function (Direction) {
Direction["Up"] = "UP";
Direction["Down"] = "Down";
Direction["Left"] = "Left";
Direction["Right"] = "Right";
})(Direction || (Direction = {}));
var value = 'UP';
if (value === Direction.Up) {
console.log('go up!');
}改造后(编译后的代码更简单,性能更好)
typescript
const enum Direction {}- 重新运行ts编译命令
shell
$ cat enums.js
var value = 'UP';
if (value === "UP" /* Direction.Up */) {
console.log('go up!');
}8.泛型(Generics)
- 创建generics.ts
typescript
function echo<T>(arg: T): T {
return arg
}
const result = echo(true)
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]]
}
const result2 = swap(['string', 123])约束泛型
typescript
function echoWithArr<T>(arg: T[]): T[] {
console.log(arg.length)
return arg
}
const arrs = echoWithArr([1, 2, 3])typescript
interface IWithLength {
length: number
}
function echoWithLength<T extends IWithLength>(arg: T): T {
console.log(arg.length)
return arg
}
const str = echoWithLength('str')
const obj = echoWithLength({length: 10, width: 20})
const arr = echoWithLength([1, 2, 3])
// echoWithLength(13) // 报错,因为整型13不存在length属性,约束泛型报错泛型在类和接口中的使用
- 泛型在类中的使用
typescript
class Queue<T> {
private data = []
push(item: T) {
return this.data.push(item)
}
pop(): T | undefined {
return this.data.shift()
}
}
const queue = new Queue<number>()
queue.push(1)
console.log(queue.pop()?.toFixed())- 泛型在接口中的使用
typescript
interface KeyPair<T, U> {
key: T,
value: U
}
let kp1: KeyPair<number, string> = {key: 1, value: 'string'}
let kp2: KeyPair<string, number> = {key: 'str', value: 2}
let arr: number[] = [1, 2, 3]
let arr2: Array<number> = [1, 2, 3]9. 类型别名,字面量 和 交叉类型
类型别名 - 给类型起一个快捷方式类型的名称
交叉类型 - 将几种类型合并起来
- 创建type-alias.ts
typescript
// 类型别名
let sum: (x: number, y: number) => number
const result = sum(1, 2)
type PlusType = (x: number, y: number) => number
let sum2: PlusType
const result2 = sum2(2, 3)
type StrOrNumber = string | number
let result3: StrOrNumber = '123'
result3 = 123
// result3 = true // 报错
// 字面量
const str: 'name' = 'name'
// const str: 'name' = 'name2' // 报错,字面量,值只能是约束的值(此处只能为‘name’)
const number: 1 = 1 // 一般用于定义常量,约束常量对应的值
type Directions = 'Up' | 'Down' | 'Left' | 'Right'
let toWhere: Directions = 'Right'
// 交叉类型
interface IName {
name: string
}
type IPerson = IName & { age: number }
let person: IPerson = {name: 'lintong', age: 29}10. 内置类型
- 创建build-in-types.ts
typescript
// global objects
const a: Array<number> = [1, 2, 3]
const date = new Date()
date.getTime()
const reg = /abc/
reg.test('abc')
// build-in object
Math.pow(2, 2)
// DOM and BOM
let body = document.body
let allLis = document.querySelectorAll('li') // 获取文档中所有li标签
allLis.keys()
// 注册一个点击事件
document.addEventListener('click', (e) => {
e.preventDefault()
})
// Utility Types
interface IPerson {
name: string
age: number
}
let lintong: IPerson = {name: 'liintong', age: 29}
type IPartial = Partial<IPerson>
let lintong2: IPartial = {name: 'lintong'}
type IOmit = Omit<IPerson, 'name'>
let lintong3: IOmit = {age: 29}11. TS配置文件 tsconfig.json

