// ts类型注解:约定了什么类型,就只能给变量赋值该类型的值
// js已有的类型:number/string/boolean/nul/undefined/symbol(生成唯一的标识) 对象类型:object
// ts原始类型:number/string/boolean
let num1: number = 10
let num2: boolean = false
let num3: string = 'a'
// ts对象类型:数组类型number[](推荐写法), Array
// ts联合类型:数组中既可以有number也可以有string类型
let arr: (number | string)[] = ['a', 1]
// ts类型别名(自定义类型)
type CustomArray = (number | string)[] // let arr1: (number | string)[] = ['a', 1] => let arr2: CustomArray = ['a', 1]
//ts函数类型
function add1(num1: number, num2: number): number { //第一、二个number是给参数加类型,第三个是给返回值加类型
return num1 + num2
}
add1(1, 2)
let add2 = (num1: number, num2: number): number => {
return num1 + num2
}
add2(1, 2)
//ts函数空类型: 如果一个函数没有返回值,那么返回值类型为void
function greet(name: string): void {
console.log('hello', name); // hello 各位同学
}
greet('中午好')
//ts函数的可选参数: 可选参数只能在必选参数之后
function mySlice(start?: number, end?: number) {
console.log('起始索引', start, '结束索引', end);
}
mySlice() // undefined / endefined
mySlice(1) // 1 / undefined
mySlice(1, 5) // 1 / 5
//ts对象类型
let person: { name: string; age: number; sayHi(name: string): void, add3: (num4: number, num5: number) => number } = {
name: 'jack',
age: 19,
sayHi(name) {
console.log('hello', name);
},
add3(num4, num5) {
return num4 + num5
}
}
//ts对象的可选属性:config可接收的参数,url请求地址,method请求方式为可选参数
function myAxios(config: { url: string; method?: string }) {
console.log(config);
}
myAxios({ url: '' })
myAxios({ url: '', method: '' })
//ts接口:当一个对象类型被多次使用,一般会用接口(interface)来表示对象的类型
interface Iperson {
name: string
age: number
sayHi(): void
}
let obj: Iperson = {
name: 'rose',
age: 28,
sayHi() { },
}
//ts类型别名对比ts接口类型:都可以给对象指定类型 不同:接口只能为对象指定类型,类型别名可以为任意类型指定别名
// ts继承 如果两个接口之间有相同的属性或者方法,可以通过继承来复用
interface Point1 { x: number, y: number }
interface Point2 extends Point1 { z: number } //Ponit2同时有xyz三个属性
// ts元祖 元祖类型可以确切的标记出有多少个元素,以及元素对应的类型,可以用来记录位置信息
let position1: [number, number] = [39, 116]
let position2: [number, String] = [39, '116']
// ts类型推论 1.声明变量并初始化的时候 2.决定函数返回值的时候 =>这两种情况,类型注解可以省略,函数参数类型注解不可省略!
// ts类型断言 使用类型断言来指定更具体的类型
// const aLink = document.getElementById('link')
// aLink.href 会报错 // 这个类型太广泛,无法操作href等a标签特有的属性。
// 解决方法:使用类型断言指定更加具体的类型,HTMLAnchorElement是HTMLElement的子类型
const aLink1 = document.getElementById('link') as HTMLAnchorElement
// const aLink1 =
aLink1.href
// ts字面量类型 除字符串外,任意js字面量(对象、数字)都可以作为类型使用
let srt1 = "hello"
const srt2 = "hello"
// 使用模式:字面量类型配合联合类型一起使用,用来表示一组明确的可选值列表
function changes(direction: 'up' | 'down' | 'left' | 'right') {
console.log(direction); // direction值只有这4个中任意一个
}
// ts枚举类型
// 枚举or字面量+枚举 更推荐:字面量类型+联合类型 :高效,简洁,直观。枚举会再js中编译成对象形式
enum Direction { Up, Down, Left, Right }
function changedirection(direction: Direction) {
console.log(direction);
}
changedirection(Direction.Up)
// 1.用enum关键字定义枚举 2.约定枚举名称,枚举中以大写字母开头,值用逗号隔开。3.定义枚举后直接用枚举名称作为类型注解
enum DIrection { Up = "Up", Down = "Down", Left = "Left", Right = "Right" }
//枚举成员的值为数字的枚举,称之为数字枚举,也可以给枚举中的成员初始化值。//字符串枚举每个成员必须要有初始值
// any类型:不推荐
//typeof 操作符,用来获取数据的类型,typeof只能用来查询变量或者属性的类型,无法查询其他形式的类型。
//ts 高级类型: class类、类型兼容性、交叉类型、泛型和keyof、索引签名类型和索引查询类型、映射类型
//class类
class person {
age: number
gender = "男"
constructor(age: number, gender: string) { //构造函数没有返回值
this.age = age //this.age是person的实例属性,age是构造函数的参数
this.gender = gender
}
}
const p = new person(18, '男') //构造函数的作用 实例属性初始化
p.age // 打印:18
p.gender // 打印:男
// class类继承两种方式:
// 1.extends(继承父类)
class Animal {
move() {
console.log('动一动');
}
}
class Dog extends Animal {
bark() {
console.log('汪汪!');
}
}
// 子类Dog继承父类Animal,则Dog的实例对象dog就同时具有了父类和子类所有的属性和方法
const dog = new Dog()
// 2.implements(实现接口) PS:实现和继承不同,继承是class类与类之间的,实现是类和接口之间的关系,是ts特有的
interface Singable {
sing(): void
}
class Person implements Singable {
sing() {
console.log('唱歌');
}
} // Person类实现接口Singable意味着Person类中必须提供Singable接口中指定的所有方法和属性
// class类成员可见性 1.public:公有成员可以被任何地方访问,可省略 2.protected(受保护的):仅对其声明所在类和子类中(非实例对象)可见 3.private(私有的)
class Animal1 {
//这个方法是受保护的
protected move() {
console.log('动一动');
}
private _run_() {
console.log('Animal1 内部辅助函数');
}
run() {
this.move() // 可以在当前类方法中通过this来调用
this._run_() // 只可以在当前类方法中通过this来调用
console.log('run');
}
}
class Dog1 extends Animal1 {
bark() {
this.move() // 可以在子类方法中通过this来调用
console.log('汪汪!');
}
}
const a = new Animal1()
// a.move() 不可以通过实例对象访问
// class类 只读修饰符:readonly,只能修饰属性,不能修饰方法
// 注意:只要是用readonly来修饰属性的时候,必须手动提供明确的类型
class Person1 {
age: number = 18
constructor(age: number) {
this.age = age
}
// readonly age: number = 18
// constructor(age: number) {
// this.age = age
// }
setage() {
this.age = 20 // 在没有只读修饰符的情况下,可以给age赋值,如果不想其他方法修改age的值,就加上只读修饰符
}
}
interface Person1 {
readonly name: string
}
// let obj: Person1 = {
// name: 'jack'
// }
// let obj: { readonly name: string } = {
// name: 'jack'
// }
// 类型兼容性
// ts采用结构化类型系统,如果两个对象具有相同的形状,认为他们属于同一类型
class point { x: number; y: number }
class point2 { x: number; y: number }
const p: point = new point2() //point与point2是两个名称不同的类,只是结构相同,所以没有类型错误,属于ts的类型兼容
// 对象之间的兼容
class point3 { x: number; y: number }
class point4 { x: number; y: number; z: number }
const p1: point3 = new point4() // point4兼容point3,成员多的可以赋值给成员少的
// 接口之间的兼容性
interface point3 { x: number; y: number }
interface point4 { x: number; y: number; z: number }
const p2: point3 = new point4()
const p3: point = new point3 //class和interface之间可以兼容,都是对象之间的兼容
// 函数之间的兼容性:参数个数,参数类型,返回类型
// 1.参数多的兼容参数少的(参数少可以赋值给多的) 2.参数类型:相同位置的参数类型要相同或兼容 3.返回值类型:只需要关注返回值类型本身即可
type F1 = (a: number) => void
type F2 = (a: number, b: number) => void
let f1: F1
let f2: F2 = f1
type F3 = (p: point3) => void //相当于2个参数
type F4 = (p: point4) => void //相当于3个参数
let f3: F3
let f4: F4 = f3 // 理解的时候可以将对象拆开,把每个属性看成一个个参数,参数少的可以赋值给参数多的
// 交叉类型 用于组合多个类型为一个类型
interface Person { name: string }
interface Contact { phone: string }
type PersonDetail = Person & Contact // 新类型同时具备这两个类型的所有属性和方法
let Obj: PersonDetail = {
name: 'jack',
phone: '133...'
}
// 交叉类型(&)和接口继承(extends)的对比
// 相同点:都可以实现对象类型的组合 不同点:两种方式实现类型组合时,对于同名属性之间,处理类型冲突方式不同
interface A {
fn: (value: number) => string
}
// interface B extends A { // 接口继承 报错:类型不兼容
// fn: (value: string) => string
// }
interface B {
fn: (value: string) => string
}
type C = A & B // 交叉类型
// 泛型 让函数等与多种类型一起工作,常用与函数、接口、class类中
// 语法:1.在函数名称后面添加<>,尖括号中添加类型变量,如Type 2.Type类型变量,是一种特殊类型的变量,它处理类型而不是值 3.该类型变量相当于一个类型容器,能够捕获用户提供的类型 4.因为Type是类型,因此可以将其作为函数参数和返回值的类型
function id
const num = id
const str = id
// 简化调用泛型函数
let num1 = id(10)
let str1 = id('a')
// 泛型约束 需要为泛型添加泛型约束来收缩类型(缩小类型的取值范围)
// 1.指定更加具体的类型
function id1
console.log(value.length);
return value
}
// 2.添加约束
interface Ilength { length: number }
function id2
console.log(value.length);
return value
}
// 3.多个泛型变量
// keyof关键字接收一个对象类型,生成其键名称的联合类型
function getProp
return obj[key]
} // 函数中keyof Type实际上获取的是person对象所有键的联合类型,也就是'name|age',所以Key只能访问对象中存在的属性
let person = { name: 'jack', age: 18 }
getProp(person, 'name')