【菜狗学前端】 初探TS(结合在vue3中的使用)
佛系菜狗 2024-08-05 15:33:01 阅读 69
TypeScript是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码。我们可以将TypeScript理解成加强版的JavaScript。
简单来说:Ts是带类型语法的Js; Ts是Js的超集
TS官方网站:https://www.typescriptlang.org/
TS中文官网:https://www.tslang.cn/
一、基础语法
js已有类型:
基本类型: number, string, boolean, null, undefined, symbol,BigInt
引用数据类型:对象、数组、函数
ts新增类型:
联合类型、类型别名、接口、元祖、字面量类型、枚举、void、any、泛型等
(一) 原始类型
1.简单类型 :xx
<code>let age: number = 18;
let uname: string = "zhangsan";
let flag: boolean = false;
// null和und类型用的比较少
let nullValue: null = null;
let undefinedValue: undefined = undefined;
PS:其实最后.ts转为.js文件时void仍会变为undefined,TS中加上void一般只是为了将函数返回值和其他区分出来。
2.引用类型 :xx[]
a.数组
let arr1 = ["a", "b", "c"]
let arr3: number[] = [1, 2, 3]
let arr2: string[] = ["a", "b", "c"]
console.log(arr1, arr2, arr3);
let arr4: Array<string> = ["ok", "hello"]
console.log(arr4);
思考:数组中是可以存放多种数据类型
联合类型:|(竖线)在TS中叫做联合类型
即:由两个或多个其他类型组成的类型,表示可以是这些类型中的任意一种
b.函数
// 函数 给参数和返回值 指定类型
// 函数声明(具名函数)
function add(a: number, b: number): number {
return a + b
}
console.log(add(1, 2));
// 函数表达式(匿名函数)
let add2 = (a: number, b: number): number => {
return a + b
}
console.log(add2(1, 2));
// 箭头函数写法
type AddFn = (a: number, b: number) => number
// 通过类似箭头函数形式的语法为函数添加类型,只适用于函数表达式
let add3: AddFn = (a, b) => {
return a + b
}
console.log(add3(3, 3));
可选参数:?
使用 ? 将参数标记为可选
const fn = (n?: number) => {
}
fn()
fn(1)
函数返回值:
在js中默认返回值是und,在ts中默认返回的是void
如果指定返回值类型是 undefined 那返回值一定是 undefined
// void和undfined类型
// 如果函数没有返回值,定义函数类型时返回值的类型为void
const say = () => {
// console.log('hello ts~');
}
console.log(say());
console.log(typeof say());
const say2 = (): void => {
// console.log('hello ts~');
}
console.log(say2());
console.log(typeof say2());
// 区分:在js中默认返回值是und,在ts中默认返回的是void
// 如果指定返回值类型是 undefined 那返回值一定是 undefined
const say3 = (): undefined => {
// console.log('hello ts~');
}
console.log(say3());
console.log(typeof say3());
c.对象
// 空对象
let obj1 = {}
let obj2: {} = {}
// 指定对象里面的属性和方法
// let obj4: { name: string, say(): void } = {
let obj4: { name: string; say(): void } = {
name: "wc", // 对象里面写方法的两种写法 // say():void say: () => void
}
// 竖着写 可以换行
let obj5: {
// name: string,
name: string;
say(): void
} = {
name: "wc",
say() { }
}
(二) 类型别名 type
给某个指定类型起别名
定义类型别名,遵循大驼峰命名,类似于变量
什么时候是用类名别名?
当同一类型(引用)被多次使用,可以通过类型别名简化
// 语法:type 类型别名=具体类型
type A = (string | number)[]
let arr9: A
arr9 = [1, "a", 3]
交叉类型 &
// type 交叉类型
type APoint2D = {
x: number,
y: number
}
type APoint3D = APoint2D & {
z: number
}
let o: APoint3D = {
x: 1,
y: 2,
z: 3
}
(三) 接口 interface (可继承extends)
interface 后面跟的是接口名称
注意:接口的每一行只能有一个属性或者一个方法 每一行不需要加分号
interface Person {
name: string
age: number
say: () => void
}
let p: Person = {
name: "wangcai",
age: 18,
say() { }
}
console.log(p);
// 接口是可继承的
// 2D坐标
interface Point2D {
x: number
y: number
}
let p2: Point2D = {
x: 1,
y: 2
}
console.log(p2);
// 如何实现继承?
// 使用extends实现接口继承,达到类型复用
// 继承后 接口A 拥有了接口B的所有属性和函数的类型声明 interface Point3D extends Point2D { z: number}
let p3: Point3D = {
x: 1,
y: 2,
z: 3
}
(四)interface和type的区别
1.type是起别名,interface 是自己发明类型 自定义类型
// 会报错
// type APerson = {
// name:string
// }
// type APerson = {
// age:number
// }
interface Person1 {
name1: string
};
interface Person1 {
age1: number
};
// 类型合并
const c1: Person1 = {
name1: "wc",
age1: 18
}
2.type不可以重复定义,interface可以重复定义会合并
3.type支持对象类型和其他类型,interface只支持对象类型
4.type复用:交叉类型 &,interface复用:可以继承 extends
二、ts在vue3中的使用
(一)ref和ts
// 手动指定类型
const count =ref<number>(0)
<template>
<div>{ { count }}</div>
<ul>
<li v-for="item in list" :key="item.id">code>
{ { item.name }}
</li>
</ul>
</template>
<script setup lang="ts">code>
import { ref, reactive } from "vue"
// 手动指定类型const count =ref<number>(0)
// 自动类型
const count1=ref(0)
type ToDoItem={
id:number;
name:string;
done:boolean
}
// [{},{},{}]
const list=ref<ToDoItem[]>([])
setTimeout(()=>{
list.value=[
{ id: 100, name: "吃饭", done: false },
{ id: 101, name: "睡觉", done: false },
]
},1000)
</script>
(二)reactive和ts
type Book={
title:string;
year?:number
}
const book:Book=reactive({
title:"ts语法基础"
})
<template>
{ { book.title }} -- { { book.year }}
</template>
<script setup lang="ts">code>
import { ref, reactive } from "vue"
// 1.手动指定类型
type Book={
title:string;
year?:number
}const book:Book=reactive({
title:"ts语法基础"
})
book.year=2023
// 2.自动类型推导
const Book=reactive({title:"ts语法基础2"})
</script>
(三)computed和ts
const doubleCountB = computed<string(() => (count.value * 2).toFixed(2))
<template>
{ { count }} -- { { doubleCount }} -- { { doubleCountB }}
{ { typeof count }} -- { { typeof doubleCount }} -- { { typeof doubleCountB }}
</template>
<script setup lang="ts">code>
import { ref, computed } from "vue"
const count = ref(205)
// 1.自动类型推导
// toFixed(2)保留2位小数,且返回值类型为string
const doubleCount = computed(() => (count.value * 2).toFixed(2))
// 2.指定计算属性的类型
const doubleCountB = computed<string>(() => (count.value * 2).toFixed(2))
</script>
(四)defineprops和ts(父传子)
defineProps<{
money:number;
car?:string
}>()
Child.vue
<template>
<div class="">code>
<p>{ { money }}</p>
<p>{ { car }}</p>
</div>
</template>
<script setup lang="ts">code>
// vue3基本写法
// defineProps({
// money:{
// type:Number,
// required:true
// }
// })
// ts基本语法
// defineProps<{
// money:number;
// car?:string
// }>()
// ts+有默认值的写法
withDefaults(
defineProps<{
money:number;
car?:string
}>(),{
money:666,
car:"xiaomi"
}
)
</script>
App.vue
<template>
<div>
<!-- 父传子 -->
<Child :money="money"></Child>code>
</div>
</template>
<script setup lang="ts">code>
import { ref} from "vue"
import Child from "./components/Child.vue"
const money=ref(666)
const car=ref('大众')
</script>
(五)defineEmits和ts(子传父)
const emit =defineEmits<{
(e:"changeMoney",money:number):void;
(e:"changeCar",car:string):void;
}>()
Child.vue
<template>
<p>{ { money }}</p>
<button @click="emit('changeMoney', 800)">改money</button>code>
<p>{ { car }}</p>
<button @click="emit('changeCar', '宝马')">改car</button>code>
</template>
<script setup lang="ts">code>
// vue3基本写法
// const emit = defineEmits(["changeMoney", "changeCar"])
// ts写法
defineProps<{
money: number;
car?: string;
}>()
const emit =defineEmits<{
(e:"changeMoney",money:number):void;
(e:"changeCar",car:string):void;
}>()
</script>
App.vue
<template>
<!-- 子传父 -->
<Child
:money="money"code>
:car="car"code>
@change-money="money=$event"code>
@change-car="car=$event"code>
></Child>
</template>
<script setup lang="ts">code>
import { ref} from "vue"
import Child from "./components/Child.vue"
const money=ref(666)
const car=ref('大众')
</script>
(六)事件处理和ts :Event
as 断言
e:Event
<template>
<input type="text" @change="handleChange" value="hi">code>
</template>
<script setup lang="ts">code>
// 不处理类型
// const handleChange=(e)=>{
// console.log(e.target.value)
// }
const handleChange=(e:Event)=>{
// as 断言
// e.target 事件源
console.log((e.target as HTMLInputElement).value);
}
</script>
(七)ref写在标签上获取 :HTMLInputElement
const input = ref<HTMLInputElement | null(null)
<template>
<div>
<input type="text" ref="input">code>
</div>
</template>
<script setup lang="ts">code>
import { onMounted, ref } from 'vue'
const input = ref<HTMLInputElement | null>(null)
// 页面加载完毕调用钩子函数
onMounted(()=>{
input.value?.focus()
})
</script>
(八)非空断言 !
// ! 非空断言(方法一)
input.value!.value = "456" //可以赋值
// 类型守卫(方法二)
if (input.value) {
input.value.value = "789" //可以赋值
}
<template>
<div>
<input type="text" ref="input" value="123">code>
</div>
</template>
<script setup lang="ts">code>
import { onMounted, ref } from 'vue'
const input = ref<HTMLInputElement | null>(null)
// 页面加载完毕调用钩子函数
onMounted(() => {
// 自动获取焦点
input.value?.focus()
// 使用ES6 输入框没有获取到,对于可能出现null,
console.log(input.value?.value);
// ?可选参数 可选链 报错 因为不能赋值
// input.value?.value = "456"
// ! 非空断言(方法一)
input.value!.value = "456" //可以赋值
// 类型守卫(方法二)
if (input.value) {
input.value.value = "789" //可以赋值
}
})
</script>
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。