TS是带类型语法的JS : TypeScript
是一种带有 类型语法
的 JavaScript 语言,在任何使用 JavaScript 的开发场景中都可以使用。
JavaScript 代码 没有明确的类型 let age = 18
TypeScript 代码 有明确的类型,可以指定age是number类型(数值类型) let age: number = 18
注意:TS 需要编译才能在浏览器运行。
代码执行
期间做类型的相关检查,所以往往你发现问题的时候,已经晚了。代码编译
期间做类型的相关检查,如果有问题编译是不通过的,也就暴露出了问题。编写代码
的时候就能发现问题,更准确更快的处理错误。TS优势总结
全局安装:
# npm 安装
npm i -g typescript
# yarn 安装
yarn global add typescript
# 部分mac电脑安装需要sudo权限
# sudo npm i -g typescript
# sudo yarn global add typescript
查看版本:
tsc -v
编译ts流程:新建hello.ts文件 ====> 在当前根目录打开命令窗口,执行tsc hello.ts
命令,同级目录生成 hello.js
文件===>验证一下
webpack
vite
等工具自动构建编译。创建 vue-ts 项目
任选一种方式:
# npm 6.x
npm create vite@latest my-vue-ts-app --template vue-ts
# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-ts-app -- --template vue-ts
# yarn
yarn create vite my-vue-ts-app --template vue-ts
# pnpm
pnpm create vite my-vue-ts-app --template vue-ts
首先了解一下js的数据类型有哪些:js的数据类型一共有8种,
简单数据类型:number, string ,boolean, null,undefined,Symbol,BigInt
复杂数据类型:Object【Object是个大类,function函数、array数组、date日期...等都归属于Object】
一 类型注解
约定了什么类型,就只能给该变量赋值什么类型的值,否则报错。
// 约定变量 age 的类型为 number 类型
let age: number = 18;
age = 19;
二 数组类型
// 数组类型
let arr: Array
= [1, 2, 3, 4, 5] let arr1: number[] = [1, 2, 3, 4, 5]
let arr2: string[] = ['1', '2', '3']
三 联合类型:
|
连接,代表类型可以是它们当中的其中一种,这种类型叫:联合类型
第一种:
let count: number | string = 2 // count的值只能是number类型或者string类型
第二种:
let obj: { id: number, name: string } = { id: 1, name: 'jack' }
let obj2: { id: number, name: string } | number | number[ ] = { id: 1, name: 'jack' }
obj2 的值类型可以是这几种:{ id: number, name: string } | number | number[ ]
第三种:
let arr3: ( number | string | number[ ] )[ ] = [1, 2, 3, '4', [1, ‘2’] ]
第四种:
let list: {
id: number;
name: string;
hobby: string[];
family: {
mather: string;
};
} = {
id: 1,
name: 'jack',
hobby: ['游泳', '唱歌'],
family: {
mather: '母亲'
}
}
参数
和 返回值
指定类型。分别指定
参数和返回值类型同时指定
参数和返回值类型// 普通函数类型 定义函数的参数类型是number,返回值类型是string
function add(a: number, b: number): string {
return '12'
}
add(1, 2)
// 箭头函数 定义函数的参数 返回值类型都是number
const add1 = (a: number, b: number): number => {
return 12
}
add1(1, 2)
// 使用函数类型别名
同时指定
参数和返回值类型:type F = (a: number, b: number) => string
const add2: F = (a, b) => {
return '12'
}
add2(1, 2)
const add2: (a: number, b: number) => number= (a, b) => {
return a
}
add2(1, 2)
简化
该类型的使用// 对象类型别名
type N =number
type S=string
type T = {
id: N;
name: S;
hobby: S[ ];
family: {
mather: S;
}
say: () => string
fn(): void
}
let list: T = {
id: 1,
name: 'jack',
hobby: ['游泳', '唱歌'],
family: {
mather: '母亲'
},
say: () => {
return '123'
},
fn() {
return 456
}
}
// 函数类型别名:
type F = (a: number, b: number) => string
const add3: F = (a, b) => {
return '12'
}
add2(1, 2)
对于返回值不确定的可以使用void void跟undefined是两种类型 类型是undefined 值只有undefined
例如: 后台返回的数据 不确定类型的情况下 可以用void 函数的返回值不确定类型的情况下也可以用void
type F1 = (a: number, b: number) => undefined
const add4: F1 = (a, b) => {
return undefined
}
add4(1, 2)
// 字面量类型
// let num:123=123 字母量类型
// num=456 会报错
const num2: 456 = 456
let num3: number = 789
num3 = 666
可选参数
语法,参数后加 ?
即可// 第一种
type F2 = (a?: number, b?: number) => undefined
const add5: F2 = (a, b) => {
return undefined
}
add5() //可以不传参 在上面的a后面加?
// 函数的可选参数有两种情况:箭头函数跟普通函数 ?写的位置不一样 如下:
type list1 = {
id: number
name: string
hobby: string[]
family: {
mather: string
},
say?: () => string
fn?(): void
}
let list4: list1 = {
id: 1,
name: 'jack',
hobby: ['游泳', '唱歌'],
family: {
mather: '母亲'
},
// say: () => {
// return '123'
// },
// fn() {
// return 456
// }
}
interface
后面是接口名称,和类型别名的意思一样。简单来说,接口后面是接类型。//接口 interface 没有等号 专门定义对象数据类型
interface Iperson {
id: number
name: string
}
const obj1: Iperson = {
id: 1,
name: 'jack'
}
// type 类型别名 有等号 可以定义所有数据类型
type Toby={
id:number
name:string
}
const obj1:Toby={
id:1,
name:'jack'
}
使用 extends 实现接口继承,达到类型复用
// 接口 interface 继承 extends 不用extends 就重复定义会合并
interface Iperson {
id: number
name: string
}
interface Iperson2 extends Iperson { //Iperson2 继承 Iperson 的类型
age: number
hobby: string[]
}
const obj1: Iperson2 = {
id: 1,
name: 'jack',
age: 18,
hobby: ['rap']
}
// 类型别名 type & 继承 type不可以重复定义
type Tperson = {
id: number
name: string
}
type Tperson2 = Tperson & {
age: number
hobby: ['rap']
}
const obj3: Tperson2 = {
id: 1,
name: 'jack',
age: 18,
hobby: ['rap']
}
interface 和 type 的相同点和区别 小结:
extends
, type 使用 &
// 类型断言:as
// 但是我们明确知道获取的是一个 A 元素,可以通过 类型断言 给它指定一个更具体的类型。标签的类型
const aLink = document.getElementById('link') as HTMLAnchorElement //获取的元素是一个a标签
const img = document.getElementById('img') as HTMLImageElement
type T2 = {
id: number
name: string
arr: number[]
}
let obj7 = {} as T2 //类型断言
obj7.arr = [1, 2] //obj7. 后面会有提示 只能拿到以下3个
obj7.id = 3
obj7.name = 'jack'
// 类型推断: typeof 后面接值 ====> 返回的是 类型
const obj4 = {
id: 1,
name: 'jack'
}
type Tperson4 = typeof obj4 // 进行类型推断
let obj5 = {} as Tperson4 // 结合as类型断言
obj5.id = 2
obj.name = 'rose'
any
的使用越多,程序可能出现的漏洞越多,因此不推荐使用 any
类型,尽量避免使用。// 类型推断: typeof 后面接值 ====> 返回的是 类型
const obj4 = {
id: 1,
name: 'jack'
}
type Tperson4 = typeof obj4 // 进行类型推断
let obj5 = {} as Tperson4 // 结合as类型断言
obj5.id = 2
obj.name = 'rose'
// keyof 后面接的是类型 返回的也是类型
const res = {
info: 'admin',
introduce: '数据',
mobile: 13020203030
}
type Tt = typeof res
type key = keyof Tt // 返回的是 "info" | "introduce" | "mobile" 返回的是类型中的键 组成的字面量联合类型
泛型别名
// 泛型别名
type user = {
id: number
age: number
}
type Goods = {
hobby: string[]
gender: string
}
type Data
= { id: number
get: string
res: T
}
type userInfo = Data
/* 返回的结果如下
{
id:number
get:string
res: {
id: number
age: number
}
}
*/
type userInfo1 = Data
/* 返回的结果如下
{
id:number
get:string
res: {
hobby: string[]
gender: string
}
}
*/
type Data1
= { id: number
get: string
res: T
code: S
}
type userInfo3 = Data1
泛型接口
// 泛型接口 没有等号=
interface Iperson1
{ id: number
code: number
messgae: S
data: T
}
type Iperson3 = Iperson1
// 验证类型Iperson3
const obj6: Iperson3 = {
id: 1,
code: 2,
messgae: '456',
data: 789,
}
泛型函数
// 泛型函数
// 函数名称后加上
, Q是类型参数,是个类型变量// 当你调用函数的时候,传入具体的类型,Q 或捕获到这个类型,函数任何位置均可使用。
type Q = number
function fn1
(a: Q): Q {return a
}
// add1
('123') //会提示不能赋值stringfn1('123') //会自动进行类型推断
// 泛型函数继承
type F3 = string
function fn2
(a: Q): Q {return a
}
fn2('1')
// 泛型函数 继承 类型推断
const c1 = { id: 1 }
function fn3
(a: Q): Q {return a
}
fn3({ id: 2 })
// 泛型函数 继承 keyof
type c2 = { id: 1 } //keyof c2 返回c2类型的键 、Q extends keyof c2 Q继承c2返回的类型中的键 也就是字面量id
function fn4
(a: Q): Q {return a
}
fn4('id') //参数 只能输入'id'
枚举
// 枚举 enum
// 可以设定初始值
enum Day {
sunday,
monday,
tuesday,
wednesday,
thursday,
friday,
saturday
}
function fn5(Day: Day) {
return Day
}
fn5(Day.sunday)
前提:script 加上
lang="ts"
才能写ts代码
defineProps的TS写法
父传:
// 父传
import son from './components/son.vue'
const sum = 100
我是父组件
子收:
//1 v3的写法
// defineProps({
// money: Number,
// car: {
// type:String
// },
// num: String
// })
//2 ts写法 没有默认值的写法: 泛型的写法
// defineProps<{
// money: number
// num: string
// car?: string //可选参数
// }>()
// 3 ts写法 有默认值的写法:withDefaults(defineProps<>(),{默认值})
// 父组件没传car的情况下就显示默认值 ,父组件传值了显示传的值
// withDefaults(defineProps<{
// money: number
// num: string
// car?: string //可选参数
// }>(), {
// car: '凯迪拉克'
// })
// 4 有默认值的简易写法 父组件没传car的情况下就显示默认值 car = '凯迪拉克'
let { money, num, car = '凯迪拉克' } = defineProps<{
money: number
num: string
car?: string
}>()
===vue3
===={{ money }}==={{ num }}==={{ car }}
我是子组件son
vue3写法:
const emit = defineEmits(['事件名'])
2.defineEmits 通过泛型参数来定义,可以实现更细粒度的校验:
ts写法:
ts 泛型 const emits = defineEmits<>()
const emits = defineEmits<{
(e: 'handel', s: string): void
(e: 'handel2', s: number): void
}>()
子传:
子传
// 第一种子传父 vue3
// const emits = defineEmits(['handel'])
// const btn = () => {
// emits('handel', '我是子组件son传的值')
// }
// 第二种子传父 ts泛型 const emits = defineEmits<>()
const emits = defineEmits<{
(e: 'handel', s: string): void
(e: 'handel2', s: number): void
}>()
const btn = () => {
// 子向父传值
emits('handel', '我是子组件son传的第一个值')
}
const btn2 = () => {
// 子向父传值
emits('handel2', 123456)
}
我是children子组件
父收
// 父收
import children from './components/children.vue'
// 第一种方法
// const msg = () => {
// console.log('handel')
// }
// 第二种方法:
import { ref } from 'vue'
const msg = ref('')
const msg2 = ref(1)
御剑乘风来,除魔天地间!===vue3
我是父组件
===={{ msg }}
===={{ msg2 }}
ref()
会隐式的依据数据推导类型
import { ref } from "vue";
type T = {
id: number
name: string
}
let list = ref
([ ]) // 表示一个list这个数组里面的每一个数据都是T这样的对象类型{id:123,name:"jack"} list.value.push({ id: 123, name: 'rose' }) //
===vue3
reactive()
也会隐式的依据数据推导类型
推荐使用ref( )
computed()
会从其计算函数的返回值上推导出类型:import { ref, computed } from "vue";
type T = {
id: number
name: string
}
let list = ref
([]) // 表示一个list这个数组里面的每一个数据都是T这样的对象类型{id:123,name:"jack"} list.value.push({ id: 123, name: 'rose' }) //
// const newList = computed(() => { //vue3写法
// return list.value
// })
const newList = computed
(() => { //泛型写法 T[]返回值的类型 return list.value
})
let num = ref(100)
const newNum = computed
(() => { return (num.value * 10).toFixed(2) //保留2位小数
})
御剑乘风来,除魔天地间!===vue3
===={{ newList }}==={{ newNum }}
import { ref, onMounted } from "vue"
// 事件对象 ===ts
const handelChange = (e: Event) => {
// 类型断言
let val = (e.target as HTMLInputElement).value
console.log(val, 99);
}
// ref获取dom元素
const dom = ref
(null) onMounted(() => {
// console.log(dom.value?.value,77);
// if(dom.value){
// console.log(dom.value.value,88);
// }
// ts非空断言
console.log(dom.value!.value, 88);
})
御剑乘风来,除魔天地间!===vue3
项目中安装的第三方库里面都是打包后的JS代码,但是我们使用的时候却有对应的TS类型提示,这是为什么呢?
TS类型声明文件
什么是类型什么文件?
TS 中有两种文件类型:.ts
文件 .d.ts
文件作用是啥?
既包含类型信息又可执行代码
只包含类型信息
的类型声明文件小结:
implementation
代码实现文件declaration
类型声明文件首先,常用的第三方库都有相应的类型声明文件,只是使用的方式不同而已。
情况1:库本身自带类型声明文件
node_modules/axios
可发现对应的类型声明文件。情况2:由 DefinitelyTyped 提供
@types/jquery
类型声明包@types/jquery
)@types/*
类型声明包后,TS 也会自动加载该类声明包,以提供该库的类型声明自定义类型声明文件 共享类型
使用类型声明文件提供需要共享的TS类型
.ts
文件中都用到同一个类型,此时可以创建 .d.ts
文件提供该类型,实现类型共享。index.d.ts
类型声明文件。export
导出(TS 中的类型也可以使用 import/export
实现模块化功能)。.ts
文件中,通过 import
导入即可(.d.ts
后缀导入时,直接省略)。