整理一下所知道的 Vue3 + TS 的基础知识点【会不定时更新】。
若还没看过 Vue3文档 或 TS搭配Vue3使用 的官方文档的童鞋,还是记得看看 官方文档
编译时就知道变量类型的是静态类型,运行时才知道一个变量类型的叫做动态类型。 java 是静态类型, js 是动态类型。
不允许隐式转换的是强类型,允许隐式转换的是弱类型。 java 是强类型, js 是弱类型。
那ts到底是什么类型的语言,很明显, ts 是静态类型语言,因为它需要经过编译。但是 ts不是强类型,因为它可以允许隐式类型转换。
let isBool: boolean
let num: number = 10
isBool = !num // ok
ECMAScript 的超集 (stage 3)
编译期的类型检查
不引入额外开销(零依赖,不扩展 js 语法,不侵入运行时)
编译出通用的、易读的 js 代码
Typescript = Type + ECMAScript + Babel-Lite
增加了代码的可读性和可维护性
减少运行时错误,写出的代码更加安全,减少 BUG
享受到代码提示带来的快感
重构神器
<script set lang="ts">
// 代码片段....
</script>
声明了变量的类型,那么这个变量就有了静态类型的特性,ts中使用:
操作符来声明类型。
// boolean 类型
let bool: boolean = true
console.log(bool)
// number 类型
// 支持浮点数、十进制和十六进制字面量、ES5的二进制和八进制字面量
let decLiteral: number = 6
let hexLiteral: number = 0xf00d
let binaryLiteral: number = 0b1010
let octalLiteral: number = 0o744
// string 类型
let str: string = 'hellow word'
let strL: string = `---${str}的字符串长度是${str.length}`
在元素类型后面接上 [],表示由此类型元素组成的一个数组。
let numArr: number[] = [1, 2, 3]
let anyArr: any[] = [1, '2', true]
// Array<元素类型>
let arrNum: Array<number> = [1, 2, 3]
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
Ts 内置类型之 Tuple
let tupleArr1: [string, number]
tupleArr1 = ['', 0] // ok
tupleArr1 = [1, false] // error
let tupleArr2: [number, string, boolean] = [1, '2', false] // ok
TS中,枚举就是一组常量的集合,但是和集合不同,枚举可以通过变量的值来得到变量,它是一个双向的过程。
默认的,第一个变量的值是0,后面的值会在前一个值上 +1,以此类推。是支持正反映射的。
enum PositionTypes {
TOP,
RIGHT,
BOTTOM,
LEFT
}
// 用值,则会得到 属性名的字符串
const top1 = PositionTypes[0] // TOP
// 用指定属性,则会得到 值
const top2 = PositionTypes.TOP // 0
console.log(top1, top2)
想改变枚举的初始值,只需要给第一个变量赋值即可。
enum PositionTypesNum {
TOP = 2,
RIGHT,
BOTTOM,
LEFT
}
// 用值,则会得到 属性名的字符串
const topNum1 = PositionTypesNum[2] // TOP
// 用指定属性,则会得到 值
const topNum2 = PositionTypesNum.TOP // 2
console.log(topNum1, topNum2)
赋值重复的时候,调用会返回最后一个。
enum PositionTypesNum {
TOP = 2,
RIGHT = 2,
BOTTOM,
LEFT
}
const topNum1 = PositionTypesNum[2] // RIGHT
const topNum2 = PositionTypesNum.TOP // 2
console.log(topNum1, topNum2)
当枚举值不是数字的时候,下一个必须设置枚举值。
enum demoTypesAny3 {
a, // a=0
b = 3, // b=3
c, // c=4
e = 'q1', // e="q1"
f = 5 // f=5,此处不能直接写f
}
console.log(demoTypesAny3)
在一个字符串枚举里,每个成员都必须初始化值,否则会报错。
enum PositionTypesStr {
TOP = 'top',
RIGHT = 'right',
BOTTOM = 'bottom',
LEFT = 'left'
}
// 字符串枚举,就只能用属性名取值了
const topStr = PositionTypesStr.TOP // 'top'
console.log(topStr)
当等号左侧和右侧重复的时候,左侧优先
enum demoTypesStr1 {
a = 'b',
b = 'a',
c = 'a'
}
const demo1 = demoTypesStr1['a'] // 'b'
const demo2 = demoTypesStr1.a // 'b'
console.log(demo1, demo2)
用 const 修饰符来声明枚举,编译后的 JS 代码将不会出现额外的声明代码。
const 枚举只能在属性或索引访问表达式中使用,或者在导入声明或导出赋值或类型查询的右侧使用,如不可console。
enum PositionTypes2 {
UP,
DOWN,
LEFT,
RIGHT
}
const enum PositionTypes22 {
SPRING = 'SPRING',
SUMMER = 'SUMMER',
AUTUMN = 'AUTUMN',
WINTER = 'WINTER'
} // 编译后看不到
const up = PositionTypes2.UP
const spring = PositionTypes22.SPRING
console.log(up, spring) // 0 'SPRING'
any(任意类型),unknown(未知的类型)。
任何类型都能分配给 unknown ,但 unknown 不能分配给其他基本类型,而 any 都能分配和被分配。
// any demo
let testAny: any
testAny = true // ok
testAny = 123 // ok
testAny.toFixed(2) // ok
let testAny1: string = testAny // ok
console.log(testAny1) // 123
// unkonwn demo
let testUnknown: unknown
testUnknown = true // ok
testUnknown = 123 //ok
testUnknown.toFixed(2) // error
let testUnknown1: string = testUnknown // error
console.log(testUnknown) // 123
用了 any 就相当于完全丢失了类型检查,所以尽量少用 any ,对于未知类型可以用 unknown。使用时,尽量将类型范围缩小,方式多样。
function getLength(value: unknown): number {
if (typeof value === 'string') {
// 因为类型保护的原因,此处 value 被判断为 string 类型
return value.length
}
return 0
}
console.log(getLength('aabbccdd')) // 8
console.log(getLength(0.001)) // 0
表示没有任何类型,一般用于定义方法的时候没有返回值。
声明一个 void 类型的变量没有什么大用,因为你只能为它赋予 undefined 和 null。
// ts定义方法 没有返回值时写 void类型
function doSomeThing(val): void {
console.log(val)
}
console.log(doSomeThing('哈哈哈哈')) // undefined
// 有返回值的时候根据规定的类型返回值,否则会保错
function getResFun():number{
// return '' // error
return 123
}
console.log(getResFun()) // 123
默认情况下 null 和 undefined 是所有类型的子类型。
可以把 null 和 undefined 赋值给 number 等其他类型的变量。
表示的是那些永不存在的值的类型,不可以被never以外的值类型所赋值。
never类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型;
变量也可能是 never类型,当它们被永不为真的类型保护所约束时。
是任何类型的子类型,可以赋值给任何类型。
没有类型是never的子类型或可以赋值给never类型(除了never本身之外),即使 any 也不可以赋值给 never。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
never 还可以用于联合类型的单位元。
type T0 = string | number | never // => type T0 = string | number
let a: T0
a = 1
console.log(a) // 1
object表示非原始类型,也就是除number,string,boolean,symbol,null或undefined之外的类型。
// 在目前TS最新的3.1版本及之前,不推荐使用object类型
function create(o: object | null) {
return o
}
// 更容易检查和使用键值
function create(o: Record<string, unknown> | null) {
return o
}
create({ prop: 0 }) // OK
create(null) // OK
// TODO…
// TODO…
表示多种类型的 “或” 关系,一个值可以是几种类型之一。
function getLength(val: string | any[]) {
return val.length
}
const strLen = getLength('') // ok
const arrLen = getLength([]) // ok
const otherLen = getLength(1) // error
console.log(strLen, arrLen) // 0 0
注意
若联合类型是复杂的,那么调用里面的方法等时,需要满足对应的条件,否则报错,后面的 类型保护 中有介绍如何进行处理。
interface Bird {
name: string
age: number
}
interface Fish {
name: string
codes: string[]
}
function getSmallPet(val: Bird | Fish) {
console.log(val.name) // ok
console.log(val.codes) // error
}
getSmallPet({ name: '111', age: 1 })
表示多种类型的 “与” 关系。
需要有 定义的声明类型 的所有字段,否则error。
interface Person {
name: string
age: number
}
interface Color {
name: string
codes: string[]
}
const people: Person & Color = {
name: 'people',
age: 2,
codes: ['11', '22']
}
console.log(people)
可以避免使用 enum 侵入了运行时。
// type 关键词可以声明一个类型
type PositionType1 = 'UP' | 'DOWN' | 'LEFT' | 'RIGHT'
const posVal: PositionType1 = 'UP'
console.log(posVal) // 'UP'
// 具值联合类型
type PositionType2 = 'top' | 'center' | 'bottom'
let posTypeVal: PositionType2 = 'top' // ok
posTypeVal = 'left' // error 不能将类型 "left" 分配给类型 "PositionType2"
posTypeVal = 'bottom' // ok
console.log(posTypeVal) // 'bottom'
// 数组联合类型
const arr: (number | string)[] = []
arr.push(1) // ok
arr.push('hello') // ok
arr.push(true) // error 类型 "true" 的参数不能赋给类型 "string | number" 的参数。
console.log(arr) // [1, 'hello']
type 与 interface 的区别
使用 TS 的 is 关键词
function isString(value: unknown): value is string {
return Object.prototype.toString.call(value) === '[object String]'
}
function isNumber(value: unknown): value is number {
return Object.prototype.toString.call(value) === '[object Number]'
}
function fn(val: string | number) {
if (isString(val)) {
return val.length
} else if (isNumber(val)) {
return undefined
}
}
const val1 = 111
const val2 = '222'
console.log(fn(val1), fn(val2)) // undefind 3
typeof 返回一个表达式的数据类型的字符串,返回结果为 JS 基本的数据类型,包括number,boolean,string,object,undefined,function。语法为 typeof(data) 或 typeof data。
function getNumber(value: string | number) {
if (typeof value === 'number') {
return value
}
if (typeof value === 'string') {
return Number(value)
}
throw new Error(`Expected string or number, got '${value}'.`)
}
getNumber(1) // ok
getNumber('111') // ok
getNumber(false) // error
function getLen(x: string | any[]) {
return x.length
}
type GetLen = typeof getLen
function callback(fn: GetLen) {
fn(1) // error: 类型为 'number'的参数不能赋值给类型为 'string | any[]' 的参数
fn('11') // ok
}
class CreateByClass1 {
public age = 18
constructor() {
this.age
}
}
class CreateByClass2 {
public name = 'TypeScript'
constructor() {
this.name
}
}
function fn1(x: CreateByClass1 | CreateByClass2 | string) {
if (x instanceof CreateByClass1) {
return x.age
} else if (x instanceof CreateByClass2) {
return x.name
} else {
return x.length
}
}
在条件判断中,TS 会 自动 对 null 和 undefined 进行类型保护。
function fn2(x: string) {
if (x) {
return x.length
}
}
fn2('111') // ok
fn2() // error
fn2(null) // error
fn2(undefined) // error
把一个大的范围断言成小的、精确的范围。
type Method = 'GET' | 'POST'
function toDo(url: string, method: Method) {
console.log(url, method)
}
let option1 = {
url: 'https:',
method: 'POST'
}
// toDo(option.url, option.method) 第二个参数会报错的,因为 option.method 的值是个字符串类型,而不是自己定义的Method类型
//可以用类型断言 as 因为string类型是大的范围,缩小到'POST'和'GET'这种小范围的类型
toDo(option1.url, option1.method as Method) // https: POST
//当然也可以给option定义一个类型
type getOption = {
url: string
method: Method
}
let option2: getOption = {
url: 'https:',
method: 'POST'
}
toDo(option2.url, option2.method) // https: POST
表示确定某个标识符是有值的,跳过ts在编译阶段对它的检测。
不推荐使用非空类型断言。
function bb(value: string = '') {
//加上 ! 的意思是确保value一定是有值的
console.log(value!.length)
}
bb('ppp')
其作用是当对象的属性不存在时,会短路,直接返回undefined,如果存在,那么才会继续执行。
函数的参数后加 ?
标识可选参数,即表示允许undefined。
x?: string 等价于 x: string | undefined。
// x?: string 等价于 x: string | undefined
function fn3(x: string) {
if (x) {
return x.length
}
}
fn3('111')
// fn2(undefined) // error: 类型为 'undefined' 的参数不能赋值给类型为 'string | undefined'的参数
// fn2(null) // error
function fn4(x: string | null | undefined) {
if (x) {
return x.length
}
}
fn4(undefined) // ok
fn4(null) // ok
// 可选参数放置在最后
function fn5(a: string, x?: string | null, y?: string) {
console.log(a, x, y)
if (a) {
return a.length
}
}
fn5('111') // 111 undefined undefined
!! 将一个其他类型转换成boolean类型,类似于Boolean()。
?? 空值合并操作符,当操作符的左侧是null或者undefined时,返回其右侧操作数,否则返回左侧操作数。
let ss: string | null | undefined = undefined
console.log(ss ?? '你好') // ss ?? '你好' => 如果 ss有值而且不是null和undefined时,ss就是上面赋给的值,如果是null或者undefined,ss的值就是默认值'你好'
interface Attr {
[key: string]: string | number | null | undefind
}
const setFn = (fn: ((...arg: any[]) => void) | null) : boolean => {
if (typeof fn !== 'function') {
return false
}
console.log(fn)
retrun true
}
<script setup lang="ts">
interface PropsItem {
resolutionName: string
lineName: string[]
videoUrl: string[]
loop?: boolean
}
const props = defineProps<{
autoPlay: boolean
data: PropsItem[]
}>()
console.log(props)
</script>
<script setup lang="ts">
interface PropsItem {
size?: number,
name?: string
}
const props = withDefaults(defineProps<PropsItem>(), {
size: 50,
name: 'supper'
})
console.log(props)
</script>
<script setup lang="ts">
import { type ComputedRef, ref } from 'vue'
interface TabMenu {
title: string
active?: ComputedRef<boolean> | boolean
}
const displayDown = ref(false)
const tabMenus = ref<TabMenu[]>([
{ title: 'tab1' },
{
title: 'tab2',
active: computed(() => displayDown.value)
}
])
</script>
import { shallowRef, type DefineComponent } from 'vue'
import componentOne from './componentOne.vue'
interface ImportComp {
[key: string]: DefineComponent
}
const commonInfoContentRefs = shallowRef<ImportComp>({
one:componentOne as DefineComponent,
two:componentTwo as DefineComponent,
three:componentThree as DefineComponent,
})
觉得有用的朋友请用你的金手指点一下赞,或者评论留言一起探讨技术!