原始类型
TypeScript 拥有 JavaScript 的数据类型并且新增了更多类型
JavaScript 类型:number
、string
、boolean
、null
、undefined
TypeScript 类型:any
、type
、interface
等
any 类型
any
是逃避 TypeScript 的类型检查,可以赋任何值,但是因此可能会导致 BUG 应该尽量避免使用
在已声明未赋值时就会自动推断为 any
类型注解
如 let age:number = 18
它的 :number
就是类型注解,它约定了这是什么类型的变量只能给它赋值这个类型,给它提供了约束让代码更清晰
数组类型
TypeScript 中数组类型有两种写法 类型[]
与 Array<类型>
一般使用 类型[]
// 使用 类型[]
let listA: number[] = [1,1,4,5]
// 使用 Array<类型>
let listB: Array<string> = ['您','您','您']
联合类型
定义一个可以接收多个类型的类型注释
// 对于数组
let nyaList: (number | string | boolean)[] = [114514, '您您您', true]
let neko: Array<number | boolean> = [191919, false]
// 对于简单数据类型
let timer: number | null = null
// 对于字面量
let gender: '男' | '女' | '非二元' = '非二元'
类型别名和接口
在同一类型多次使用并且写法复杂时使用
类型别名 type
支持所有的类型,而接口 interface
只支持对象类型
类型别名 type
不允许重复命名,而接口 interface
重复命名会合并
类型别名 type
不能重新打开(向内定义新的对象注解)接口 interface
可以通过两个相同命名合并实现
类型别名
类型别名,使用大驼峰命名,类似于变量,使用它和类型注释的写法一样 type 别名 = 类型
// 数组类型别名
type CusArr = (number | string) []
let list: CusArr = [19, '您']
// 对象类型别名
type AddFnType = (num1: number, num2: number) => number
const addFn2 : AddFnType = (num1, num2) => {
return num1 + num2
}
类型别名交叉
当你一个新的类型别名 B 与一个类型别名 A 拥有相同的属性,可以使用类型别名交叉获取上个类型别名 A 的属性注解,实现的效果类似于 interface
的extends
type Point2D = {
x: number,
y: number
}
// 从 Point2D 交叉
type Point3D = Point2D & {
z: number
}
const p: Point3D = {
x: 100,
y: 100,
z: 100
}
接口
接口和类型别名类似,也使用大驼峰命名,接口只能用于定义对象的类型注解,使用方法与类型别名相同,语法 interface 名称 {}
interface Person {
name: string,
age: number,
say: () => void
}
let p: Person = {
name: 'PinocoP',
age: 28,
say() {
console.log('nai');
}
}
接口继承
当你一个新的类型别名 B 与一个类型别名 A 拥有相同的属性,就可以使用 extends
进行接口继承,语法 interface 名称
extends 需要继承的接口名称 {}
interface Person {
name: string,
age: number,
say(): void
}
interface Stu extends Person {
score: number
}
const nin: Stu = {
name: 'JuziYou',
age: 18,
score: 69,
say() {
console.log('您');
}
}
函数类型
函数声明
function 函数名(形参: 类型):返回值类型{
...
}
函数表达式
const 函数名 = (形参:类型):返回值类型 => {}
函数返回值
如果函数没有返回值就是空 void
,void
类名注解可以省略
在 JavaScript 中如果没有 return
返回值是 undefined
而在 TypeScript 中 void
和 undefined
并不相同,如果在返回值类型定义了 undefined
那么就必须 return undefined
可选参数
一个形参在可以传也可以不传的时候那就可以设置可选参数,在类型注释 ':' 前添加一个 '?' 即可,不传的情况下它的值是 undefined
,可选参数不可以设置初始值,必传参数不能写在可选参数之后
// 函数声明
function 函数名(形参?: 类型, 形参:类型):返回值类型{
...
}
// 函数表达式
const 函数名 = (形参?:类型, 形参:类型):返回值类型 => {}
对象类型
对象类型有空对象和有属性的对象以及有属性和方法的对象(废话)
定义属性注解和可选属性和之前的那些方法差不多
对象类型在多个属性注解之间可以使用 ,
也可以使用 ;
甚至可以直接换行
// 空对象
let person1 = {} = {}
// 有 属性 的对象
let person2: { name: string} = {
name: 'juziyou'
}
// 有属性有方法的对象
let person3: { name: string, say(): void} = {
name: 'JuziYou',
say(){}
}
// 在多个对象属性间可以用 `,` 也可以用 `;` 甚至可以直接换行
let person4: {
name: string;
age: number
} = {
name: 'JuziYou',
age: 18
}
let person5: {
name: string
age: number
} = {
name: 'JuziYou',
age: 18
}
// 给箭头函数定义
let person6: {
name: string,
say: () => void
} = {
name: 'JuziYou',
say: () => console.log('喵')
}
// 接收一个多属性可选
// 列如 axios 的 config 中接收 url 和 method 其 method 可选
const axios = (config: {url: string, method?:string}) => {}
// 使用类型别名
type Config = (config: {url: string, method?:string}) => {}
const axios2 = (config: Config) => {}
类型推断
在 TypeScript 中存在类型推断机制,在没有指定类型的情况下会自动推断类型
// let num: number
let num = 114514
// fn(num1: number, num2:number): number
function fn(num1: number, num2:number) {
return num1 + num2
}
字面量
在 TypeScript 中 let
了一个字面量相当于 const
了一个常量如 let nya: 'JuziYou' = 'JuziYou'
那么它就只能赋值为 'JuziYou'
,let
的自动推断是赋予值的数据类型、const
的自动推断是赋予的值
// let neko: string
let neko = 'JuziYou'
// const nya: 'JuziYou'
const nya = 'JuziYou'
断言
当明确的知道数据类型就可以使用断言,as
断言它跟的类型是一个更加具体的类型
// 假设此时 #nya 是一个 <a> 标签
const link = document.getElementById('nya') as HTMLAnchorElement
非空断言
在 .
前面加 !
来添加非空断言,告诉他一定有某个属性,比如 nya!.neko
就是告诉 TypeScript 在 nya
下一定有 neko
泛型
泛型是定义不确定是什么类型,使用的时候才知道,提高服用性和灵活性,一般使用大驼峰命名
泛型别名
在定义的别名后加上 <泛型参数>
就是接收泛型,然后在下面的类型注解使用 泛型参数
,然后在使用时在类型注解的类型别名后加上 <类型参数>
即可使用
type User = {
name: string,
age: number
}
type Goods = {
id: number,
name: string
}
type Data<Type> = {
message: string,
code: number,
data: Type
}
// 假设是请求到用户信息
let user: Data<User> = {
message: 'Okay',
code: 200,
data: {
name: 'Mikan',
age: 18
}
}
// 假设是请求到商品信息
let goods: Data<Goods> = {
message: 'Okay',
code: 200,
data: {
name: '大猫猫抓板',
id: 0
}
}
泛型接口
在定义的接口名后加上 <泛型参数>
就是接收泛型,然后在下面的类型注解使用 泛型参数
,然后在使用时在类型注解的接口名后加上 <类型参数>
即可使用
interface IDs<Type> {
id: ()=> Type,
ids: ()=> Type[]
}
// 假设获取一个 ID 列表
const idList: IDs<number> = {
id(){
return 114514
},
ids(){
return [19,1919,191919]
}
}
泛型函数
在定义的函数名后加上<泛型参数>
就是接收泛型,然后可以使用 泛型参数
在形参和返回值的类型注释中
function newToken<Type>(token: Type): Type{
return token
}
let token: number = 191919
token = newToken<number>(114514)
泛型约束
利用了接口 interface
的 extends
接口的继承原理,来约束传入的类型
例如必须有 length
function getId<T extends {length: number}> (id:T):T {}
自定义类型声明
如果多个 .ts
文件都要用到同个类型,这时就可以创建 .d.ts
来共享该类型
全局
直接在 .d.ts
中不使用 export
按需暴露的将会生成全局自定义类型
如:在 index.d.ts
中
interface Goods {
name: string,
price: number,
brand: string
}
局部引入
TypeScript 类型也可以使用 import
和 export
来实现按需导入和导出功能,只需要再使用该 .d.ts
的 .ts
文件中 import
导入即可使用
export interface Goods {
name: string,
price: number,
brand: string
}
import {Goods} from './ts/index'
}
const goods:Goods = {
name: '猫猫猫抓板',
price: 114514,
brand: '猫猫'
}
给 JS 提供类型
在导入 .js
文件时,TypeScript 会自动加载与 .js
同名的 .d.ts
文件,提供类型声明declare
用于类型声明,为其他地方(比如,.js 文件)已存在的变量声明类型,而不是创建一个新的变量,在 interface
和 type
时不用加 declare
/util/index.d.ts
export declare const sum : (numA: number, numB:number) => number
interface Student {
name: string,
score: number
}
export declare const say: (stu: Student) => void
/util/index.js
export const sum = (numA, numB) => numA + numB
export const say = (stu) => console.log(stu.name, stu.score);
index:
import { sum, say } from './util'
sum(1,2)
say({name: 'Nya', score: 66})
在 Vue 组合式 API 中使用
Props
基本使用
使用 defineProps<泛型>()
来来定义接收的数据类型
示例:
const props = defineProps<{money: number}>()
定义默认值
如果定义默认值需要使用 withDefaults
它第一个值接收一个函数写defineProps
,第二个值写一个对象里面写接收的默认值
示例:
// const props = withDefaults(defineProps< 泛型 >(), {
// 接收值: 默认值
// })
const props = withDefaults(defineProps<{age: number, uname?: string}>(), {
uname: 'JuziYou'
})
语法糖 ⚗️
withDefaults
看起来比较复杂,所以可以使用响应式语法糖,目前还是实验性功能所以需要显式启用它,然后通过 const {接收值} = defineProps<泛型>()
使用
示例:
const {age, uname = 'JuziYou'} = defineProps<{
age: number,
uname?: string
}>()
Emit
不知道怎么解释就直接写上算了(摆)
子组件:event
和 payload
是自己定义的参数名 event
是触发事件的自定义事件名 payload
是传参
const emit = defineEmits<{
(event: 'changeNya', payload:number):void
}>()
父组件:
const changeNyaFn = (nya: number) => {
console.log('Nya', nya);
}
ref
通过 ref<泛型>(需要响应式的数据)
定义 ref
简单数据类型
定义简单数据类型 ref<泛型>(需要响应式的数据)
定义 ref
示例:
const uname = ref<string>('JuziYou')
自动推导
一般情况下 TypeScript 会自动推导它的数据类型所以可以 ref(需要响应式的数据)
这样写
示例:
// const uname: Ref<string>
const uname = ref('JuziYou')
复杂数据类型
如一个泛型为 Person 类型的数组
type Person = {
id: number,
uname: string,
address: string
}
const personList = ref<Person[]>([])
personList.value.push({
id: 1,
uname: 'JuziYou',
address: 'Nya'
})
reactive
使用 reactive
时推荐直接给变量指定类型
type Car = {
brand: string,
price: number,
color?: string
}
const car:Car = reactive({
brand: '橘子',
price: 114514
})
car.color = "橘色"
computed
computed
一般会自动推导数据类型,也可以使用泛型指定
自动推导:
const nyaNum = ref(18)
// computed<number>
const nyaCount = computed(()=> nyaNum.value ** 2)
泛型指定:
const nyaNum = ref(18)
const nyaCount = computed<number>(()=> nyaNum.value ** 2)
事件
事件对象使用 Event
类型注释,通过类型断言来解决可能是个 null
的问题
如:获取 <input type="text" @change="changFn">
的 value
const changFn = (event: Event) => {
// 使用类型断言,断言 even.target 是一个 input
console.log((event.target as HTMLInputElement).value)
}
ref 获取 DOM
const ref的值 = ref<类型 | null>(null)
来获取对应的 DOM
如:获取 ipt
再载入后默认聚焦
<script setup lang="ts">
const ipt = ref<HTMLInputElement | null>(null)
onMounted(()=>{
ipt.value?.focus()
})
</script>
<template>
<input type="text" ref="ipt" value="Nya">
</template>
Use "CC BY-NC-SA 3.0 CN" for licensing