TypeScript笔记

TypeScript

TypeScript(简称: TS)是JavaScript的超集 (JS有的 TS 都有)

TypeScript = Type +JavaScript (在JS 基础之上,为Js 添加了类型支持)

TypeScript是微软开发的开源编程语言,可以在任何运行JavaScript的地方运行

// TypeScript 代码: 有明确的类型,即 : number(数值类型)
let age:number = 18
// JavaScript 代码: 无明确的类型
let age = 18

TypeScript介绍

从编程语言来区分,TypeScript届于静态类型的编程语言,JS届于动态类型的编程语言

静态类型:编译期做类型检查,动态类型:执行期做类型检查

代码编译和代码执行的顺序:1 编译 2执行

对于JS来说:需要等到代码真正去执行的时候才能发现错误(晚)。

对于 TS 来说:在代码编译的时候(代码执行前)就可以发现错误 (早)

TypeScript使用

安装编译TS的工具包
npm i -g typescript
// 验证是否编译成功 tsc -v
终端内运行ts代码

两种方法

1.
tsc xxx.ts  // 将ts文件编译成js  
node xxx.js   // 运行 
2.  
npm i -g ts-node  // 下包
ts-node xxx.ts   // 运行 

// 报错解决:用tsc --init命名,在根目录下生成配置文件 tsconfig.json

TypeScript常用类型

类型注解

: number就是类型注解,为变量添加类型约束

为变量指定类型
原始类型
let age: number = 18  // 数字型
let age: string = '18'  // 字符串型
let age: boolean = false  // 布尔型
let age: null = null  // null
let age: undefined = undefined // undefined
let age: symbol = Symbol() // symbol
数组类型
let age: number[] = [1,2,3]  // 数值数组
let age: string[] = ['1','2','3'] // 字符串数组
// 另一种写法   let age: Array<string> = ['1','2','3']

联合类型

由两个或多个类型组成的

let age: (number | string)[] = [1,'2',3]  // 数字和字符串数组
let age: boolean[] = [true,false] // 布尔数组
元组

是另一种类型的数组,确切的知道包含多少个元素及对应类型

let arr:[number,number] = [1,2]
对象类型

对象的类型就是在描述对象的结构,属性类型之间用 ;分隔

属性采用 属性名:类型 ,方法采用 方法名:返回值类型,的形式

let obj:{name: string; age: number; sayHi: void} = {
    name:'a',
    age:18,
    sayHi(){ }
}
函数类型

实际上是给函数的参数和返回值指定类型

// 单独指定参数和返回值类型
function add(num1:number,num2:number): number {
    return num1 + num2
}

function add = (num1:number,num2:number):返回值类型 =>{
   return num1 + num2
}
// 同时指定参数和返回值类型  只适用于函数表达式
const add:(num1:number,num2:number) => number=(num1,num2)=>{
   return num1 + num2
}
// 传一个对象
function add(config: {url: string; method?: string}) {
    console.log('hello')
}
void类型

如果函数没有返回值return,那么返回值类型为 void

function add(name:string): void {
   console.log('hello')
}
可选参数

参数可以传也可以不传, 参数名称后添加 ?

可选参数只能出现在参数列表的最后

function add(name?:string): void {
   console.log('hello')
}
类型别名 (自定义类型)
type(类型别名) interface(接口)

为任意类型起别名,简化该类型的使用

两种 type(类型别名) 和 interface(接口) ,interface 只能为对象指定类型

type CustomArray = (number | string)[]  // 创建别名,可以是任意变量名
let age: CustomArray = [1,'2',3]  // 使用别名作为类型注解
interface objty {   // 创建对象别名
    name: string
    age: number
}
let obj:objty = {   // 使用别名作为类型注解
    name:'123',
    age:18
}
接口继承 extends

extends

interface P2 {x:number; y:number}
// P3继承P2的类型并添加自己的类型
interface P3 extends P2 {z:number}
// P3= {x:number; y:number; z:number}
类型断言 as

使用as关键字实现类型断言

const aLink = document.getElementById('link') as HTMLAnchorElement
// 通过类型断言 alink的类型变得更加具体,这样就可以访问a标签特有的属性和方法了
字面量类型

某个特定的字符串也可以作为TS中的类型

let str1 = 'hello'    // 他的类型为 字符串
const str2 = 'hello'   // 他的类型为 hello 就是一个字面量类型
// 因为 str2 是一个常量,值不能变化只能是hello,所以它的类型为 hello
// 除字符串外,任意js字面量(比如对象,数字等)都可以作为类型使用
枚举类型 enum

enum关键字

枚举:定义一组命名常量,描述一个值,该值可以是这些命名常量中的一个

枚举中的值以大写字母开头,多个值以逗号分割

enum Direction {Up, Down, Left, Right}
function changeDirection(direction: Direction) {
    console.log(direction)
}
// 访问枚举成员 Direction.Up
// 调用
changeDirection(Direction.Up)
数字枚举
// 枚举成员是有值的,默认从0开始自增的数值  
// 也可以给枚举中成员初始化值
enum Direction {Up=10, Down, Left, Right} 
// 如此Down=11 以此类推自增
字符串枚举
enum Direction {Up='up', Down='Down'} 
// 字符串枚举是没有自增长行为的,并且每个成员必须都有值
any类型

不推荐用,会让typescript 变成 anyscript 并没有任何错误提示

let obj:any = {x:0}
typeof运算符

用来在js中获取数据类型

也可以在类型上下文中引用变量或对象.属性的类型(类型查询)

let p = {x:1, y:2}
// 两种写法意思相同
function format(point:{x:number; y: number}) {}
function format(point: typeof p) {} // 就会把p的类型引用下来

TypeScript高级类型

class类

不仅提供了js中class语法的功能,也作为一种类型存在

class Person {}  // 创建一个类
const p = new Person()   // 创建实例对象
class类的基本使用
class Person { // 创建一个类
    age:number
    gender='男'
} 
const p = new Person()   // 创建实例对象
p.age   // 使用
class类的构造函数 constructor

constructor

class Person { // 创建一个类
    age:number
    gender:string
    // 构造函数
    constructor(age: number, gender: string) {
      this.age=age
      this.gender=gender
    }
} 
const p = new Person(18, '男')
class类的继承 extends implements

extends (继承父类)

implements (实现接口)

// extends 
class Animal {
  move() { log('1') }
}
class Dog extends Animal {  // 继承父类里所有属性和方法
  bark() { log('2') }
}
const d = new Dog()
dog.move()  // 可以访问父类里的方法
// implements  
class Animal {
  move(): void 
}
class Dog implements Animal {  
  // 里面必须提供Animal里的所有属性和方法,
  move() {
      log('2')
  }
}

class类的可见性修饰符

public (公有的)

表示公开的,可以被任何地方访问,默认可见性可省略

class Animal {
  public move(){
  	log(1)
  }
}
const a = new Animal()
a.move()  // 1
protected (受保护的)

表示受保护的,仅对其声明所在类和子类中可见,实例对象不可见

可以在子类中通过this访问受保护的

class Animal { 
    protected move(){ log(1) }
    run(){
       this.move() // 在类中通过this调用 
	}
}
const a = new Animal()
a.move()  // 报错

class Dog extends Animal {
	bark(){
		this.move() // 在子类中通过this调用
	}
}
const d = new Dog()
d.bark()  // 1
private (私有的)

表示私有的,只在当前类中可见

class Animal { 
    private move(){ log(1) }
    run(){
       this.move() // 在当前类的其他方法中通过this调用 
	}
}

class类的只读修饰符

readonly

表示只读,用来防止在构造函数之外对属性进行赋值

只能修饰属性,不能修饰方法

接口或者{}表示的对象类型,也可以使用readonly

class Animal { 
    // 只读属性
    readonly age:number = 18 // 需指定类型 否则无法赋值
    constructor(age:number){
       this.age= age  // 只能在构造函数中赋值
	}
	run() {
	   this.age= 20  // 方法中赋值 报错
	}
}
const a = new Animal(20)

类型兼容性

两种类型系统:

1.Structural Type System (结构化类型系统)

2.Nominal Type System (标明类型系统)

ts采用的是结构化类型系统,也叫做鸭子类型

对象之间的类型兼容性

对于对象类型来说,成员多的可以赋值给成员少的

// Point兼容Point2D 
class Point { x:number; y:number }
class Point2D { x:number; y:number; z:number }
const p:Point = new Point2D() // 可以
const p:Point2D = new Point() // 报错
接口之间的类型兼容性

类似于class

class 和 interface 都是对象,所以他俩也可以兼容

interface Point { x:number; y:number; }
interface Point2D { x:number; y:number; }
class Point3D { x:number; y:number; z:number }
let p1:Point 
let p2:Point2D
p2=p1
p1=p2
let p3:Point2D = new Point3D() // 也可以兼容

函数之间的类型兼容性

函数兼容比较复杂,需要考虑 参数个数、参数类型、返回值类型

参数个数

参数少的可以赋值给参数多的

type F1 = (a:number) => void
type F2 = (a:number,b:number) => void
let f1:F1
let f2:F2
f2 = f1 // 可以
参数类型

相同位置的参数类型要相同(原始类型)或兼容(对象类型)

type F1 = (a:number) => void
type F2 = (a:number) => void
let f1:F1
let f2:F2
f2 = f1 // 可以
f1 = f2 // 可以
interface Ponint2D { x:number; y:number;}
interface Ponint3D { x:number; y:number; z:number;}
// 技巧 :将对象拆开,把每个属性个数看做一个个参数
type F2 = (a:Ponint2D) => void  // 相当于有2个参数
type F3 = (a:Ponint3D) => void  // 相当于有3个参数
let f2:F2
let f3:F3
f2=f3  // 不行
f3=f2  // 可以 参数少的可以赋值给参数多的
返回值类型

只关注返回值类型本身

// 对象类型  成员多的可以赋值给成员少的
type F1 = () => {name:string}
type F2 = () => {name:string; age:number}
let f1:F1
let f2:F2
f1 = f2  // 可以
// 原始类型   返回的类型相同就可以兼容
type F1 = () => string
type F2 = () => string
let f1:F1
let f2:F2
f1 = f2 // 可以
f2 = f1 // 可以

交叉类型 &

交叉类型(&):功能类似于接口继承(extends),用于组合多个类型为1个类型(常用于对象类型)

interface Person { name: string}
interface Contact { phone: string}
type PersonDetail = Person & Contact
// 
let obj:PersonDetail = {
    name: 'abc',
    phone: '123'
}
交叉类型和接口之间的对比

相同点:都可以实现对象类型的组合

不同点:两种方式实现类型组合时,对于同名属性之间,处理类型冲突的方式不同

// 接口
interface A {
	fn:(value: number)=> string
}
interface B extends A {
	fn:(value: string)=> string
}
// 报错 (类型不兼容) 接口继承不会去处理
// 交叉类型
interface A {
	fn:(value: number)=> string
}
interface B {
	fn:(value: string)=> string
}
type C = A & B
// 可以 相当于 
fn:(value: string | number) => string

泛型

泛型是可以在保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用,常用于:函数、接口、class中。

需求:创建一个id函数,传入什么数据就返回该数据本身(也就是说,参数和返回值类型相同)

function id(value: number):number {return value}
// 比如 id(10) 调用以上函数就会直接返回10本身,但是该函数只接受数值类型,无法用于其他类型。为了让函数能够接受任意类型,可以将参数类型改为any
function id(value: any):any {return value} // 但是这样就失去了ts的类型保护


// 泛型在保证类型安全(不丢失类型信息)的同时,可以让函数等于多种不同类型一起工作,灵活可复用

// 创建泛型函数
function id<Type>(value: Type):Type {return value}
// 调用
let num = id<number>(10)  // num = 10
let str = id<string>('a')  // str = 'a'
let num = id(100)  // 也是可以的 类型可以省略

// 类型变量Type 是一种特殊类型的变量,他处理类型而不是值,相当于一个类型容器,捕获用户提供的类型,因为Type是类型,因此可以将其作为函数参数和返回值类型, Type可以是任意合法的变量名称
泛型约束

默认情况下,泛型函数的类型变量Type可以代表多个类型,这导致无法访问任何属性。 比如id(‘a’)调用函数时获取参数的长度

两种方式:1 指定更具体的类型,2 添加约束

function id<Type>(value: Type): Type{
	log(value.length)  // 报错 
    return value
}
// 因为Type可以代表任意类型,无法保证一定存在length属性,比如数字就没有长度,此时就需要为泛型添加约束。
指定更加具体的类型
// 指定更加具体的类型 [] 只要是数组就一定含有length属性
function id<Type>(value: Type[]): Type[] {
  console.log(value.length)  // 可以 
  return value
}
id([1,2,3])
通过extends为泛型添加约束
// 添加约束,通过extends 为泛型添加约束
interface Length {length:number}
function id<Type extends Length>(value: Type): Type {
  console.log(value.length)
  return value
}
id('123') // 可以
id([1,2,3]) // 可以
id({length:10}) // 可以  只要有length属性就行
多个泛型类型变量之间的约束 keyof
function id<Type, Key extends keyof Type>(obj:Type, key:Key) {
  return obj[key]
}
let per = {name:'abc',age:10}
id(per,'name')

// keyof 关键字接受一个对象类型,生成其键名称的联合类型
// 示例中 keyof Type 实际上获取的是per对象里所有key的联合类型,也就是 'name'|'age'
// 类型变量Key受Type约束,可以理解为Key只能是Type所有键中的任意一个,或者说只能访问对象中存在的属性名称
泛型接口

接口也是可以配合泛型来使用,增加灵活性和复用性

interface func<Type> {
  id: (value: Type) => Type,
  ids:()=> Type[],
}
let obj: func<string> = {
  id(value) {
    return value
  },
  ids() {
    return ['1']
  }
}
console.log(obj.id('123'));
console.log(obj.ids());
// 在接口名称后面添加<类型变量>,那么这个接口就成了泛型接口。 接口中所有成员都可以使用类型变量、 使用泛型接口时需要指定具体的类型(比如此时的 func<string>)
泛型类

class类也可以配合泛型来使用

class GenericNumber<Type> {
  value: Type
  add: (x:Type,y:Type)=> Type
}
const my = new GenericNumber<number>()
my.value = 10

// 在class名称后面添加<类型变量>,这个类就变成了泛型类。
泛型工具类型

Ts里内置了一些常用的工具类型,来简化一些ts中的操作

都是基于泛型实现的

Partial

Partial用来构造一个类型,将Type的所有属性设置为可选

interface Props {
  id: string
  children: number[]
}
type PartialProps = Partial<Props>
// 构造出来的新类型PartialProps 结构和 Props相同,并且所有属性都是可选的

let props:PartialProps = {id:'1',children:[]}
props.id='2'
Readonly

Readonly用来构造一个类型,将Type的所有属性设置为readonly只读

interface Props {
  id: string
  children: number[]
}
type ReadonlyProps = Readonly<Props>
// 构造出来的新类型PartialProps 结构和 Props相同,但所有属性都是只读的

let props:ReadonlyProps = {id:'1',children:[]}
props.id='2' // 报错 因为是只读的
Pick<Type , Keys>

Pick<Type , Keys> 从Type中选择一组属性来构造新类型

interface Props {
  id: string
  title: string
  children: number[]
}
type PickProps = Pick<Props, 'id' | 'title'>
// Pick有两个类型变量,1表示选择谁的属性,2表示选择哪几个属性
// 此处构造出来的PickProps就只有 id和title 两个属性

let props:PickProps = {id:'1',title:'a'}
// console.log(props); { id: '1', title: 'a' }
Record<Keys,Type>

Record<Keys,Type> 构造一个对象类型,属性键为keys,属性类型为Type

type RecordObj = Record<'a' | 'b' | 'c', string[]>

let obj: RecordObj = {
  a: ['a'],
  b: ['b'],
  c: ['c']
}
// Record工具类型有两个类型变量,1表示对象里有哪些属性,2表示对象里的属性类型

索引签名类型 []

当无法确定对象中有哪些属性(或者说对象中可以出现任意多个属性)此时 就用到索引签名类型了

interface AnyObj {
  [key:string]: any
}
let obj:AnyObj = {
    a:'1',
    b:2
}
// 使用[key:string]来约束该接口中允许出现的属性名称,表示只要是string类型的属性名称 都可以出现在对象中
// 这样对象obj中就可以出现任意多个属性
// key只是一个占位符,可以替换成任意合法的变量名称
// 注意:js对象中的key是string类型的

映射类型

基于一个旧的类型创建新的类型(对象类型),减少重复,提升效率

两种情况 1可以根据联合类型创建,2 可以根据对象类型创建

[key in keys] 根据联合类型创建
// 比如类型keys和types都有相同的 x y z
type keys = 'x' | 'y' | 'z'
type types = { x: number, y: number, z: number }

// 这样书写没错但x y z重复写了两次,可以用映射类型来简化
type keys = 'x' | 'y' | 'z'
type types = { [key in keys]: number }

// 映射类型是基于索引签名类型的,所以该语法类似于索引签名类型,也使用了[]
// key in keys 表示key可以是keys联合类型中的任意一个
// 映射类型只能在类型别名中使用,不能在接口中使用
[key in keyof keys] 根据对象类型创建
type keys = { x: number, y: number, z: number }
type types = { [key in keyof keys]: number }

let obj: types = {
  x: 1,
  y: 2,
  z: 3
}

索引查询类型

用于查询属性的类型

可同时查询多个

// 查询一个
type keys = { x: number, y: string, z: boolean }
type typeA = keys['x']
let A: typeA = 1
let A: typeA = '1' // 报错
//keys['a']表示查询类型keys中属性a的类型 , 所以typeA的类型是number
// 查询多个
type keys = { x: number, y: string, z: boolean }
// 两种方式
type typeA = keys['x'|'y']  // number | string
type typeA = keys[keyof keys]  // number | string | boolean

类型声明文件

用来为已存在的JS库提供类型信息, 这样在TS项目中使用这些库时,就像TS一样 都会有代码提示、类型保护等机制了

TS文件类型

TS 中有两种文件类型: 1:.ts文件 2:.d.ts文件

.ts文件
// 既包含类型信息又可执行代码
// 可以被编译成.js文件,然后执行代码
// 用途:编写程序代码的地方
.d.ts文件
// 只包含类型信息的类型声明文件
// 不会生成.js文件,仅用于提供类型信息
// 用途:为js提供类型信息
类型声明文件的使用

内置类型声明文件,第三方库的声明文件

在这里插入图片描述

创建自己的类型声明文件
  1. 创建index.d.ts 类型声明文件
  2. 创建需要共享的类型,使用export导出
  3. 在需要使用共享类型的.ts文件中 通过import导入即可(.d.ts后缀省略)

.d.ts

type keys = { x: number, y: number }
export {keys} // 导出

使用

import { keys } from '@/utils/index'
let a:keys ={
   x:1,
   y:2
}

VUE3中使用TS

  1. vscode装插件 : TypeScript Vue Plugin (Volar)

TS语法

可用TS语法来使用VUE3中的API

defineProps

子接收父传过来的值

<script setup lang='ts'>
// 定义别名
type PropsType = {
  数据名?:string   // 数据名?:数据类型  加上问号父不传值也不会报错
}
// 通过别名接收值
defineProps<PropsType>()
</script>
defineEmits

子传父 TS语法来约束传值类型

<script setup lang='ts'>
// TS语法
const emits = defineEmits<{
// 完整语法 (e:事件名,参数名1:参数类型,参数名2:参数类型):void
  (e:'自定义事件名',value:string):void
}>()
    
// 子传父触发事件
const onClick = () => {
  emits('自定义事件名', 'a')
}    
</script>
ref

约束变量类型

<script setup lang='ts'>
import { ref } from 'vue'
// 定义一个泛型  {}[] 表示对象数组
type TodoList = {
  id:number,
  name:string,
  done:boolean
}[]  
const list = ref<TodoList>([
    {id:1,name:'吃饭',done:true},
    {id:2,name:'睡觉',done:false}
])
// 如果声明的数组不符合约束的类型会报错
</script>

x:1,
y:2
}


# VUE3中使用TS

1. vscode装插件  : TypeScript Vue Plugin (Volar)

### TS语法

> 可用TS语法来使用VUE3中的API

##### defineProps

> 子接收父传过来的值

```vue
<script setup lang='ts'>
// 定义别名
type PropsType = {
  数据名?:string   // 数据名?:数据类型  加上问号父不传值也不会报错
}
// 通过别名接收值
defineProps<PropsType>()
</script>
defineEmits

子传父 TS语法来约束传值类型

<script setup lang='ts'>
// TS语法
const emits = defineEmits<{
// 完整语法 (e:事件名,参数名1:参数类型,参数名2:参数类型):void
  (e:'自定义事件名',value:string):void
}>()
    
// 子传父触发事件
const onClick = () => {
  emits('自定义事件名', 'a')
}    
</script>
ref

约束变量类型

<script setup lang='ts'>
import { ref } from 'vue'
// 定义一个泛型  {}[] 表示对象数组
type TodoList = {
  id:number,
  name:string,
  done:boolean
}[]  
const list = ref<TodoList>([
    {id:1,name:'吃饭',done:true},
    {id:2,name:'睡觉',done:false}
])
// 如果声明的数组不符合约束的类型会报错
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值