一、 ts的简单认识
认识+深入理解+熟练使用
vue3支持ts
ts是微软开发的开源、跨平台编程语言。在2012年发布。作者是安德斯.海尔斯伯格(C#首席架构师)。
TS => { {ES} + interfaces + strongly types + generic(泛型)}
ES => { {JS} + proto types + dynamic types + constructor functions }
TS comfiles to JS ( brower can't run ts) ts编译器
TS是JS的超集
特点:
1. ts可以编译出纯净、简洁的js代码,并能够在所有浏览器、node环境和es3及以上的js引擎运行。
2. ts 强大的类型系统 js开发者可以使用高效的开发工具和常用操作(静态检查和代码重构)
3.ts提供最新的和不断发展的js属性。比如异步功能和decorator
二、安装ts
全局安装
yarn global add typescript
查看是否安装成功
tsc -V
三、编写ts代码
tsc手动编译
(()=>{
function sayHi(str: string) {
return '您好呀' + str
}
let text = '小甜甜'
console.log(sayHi(text))
})()
// 浏览器可以运行ts文件,但是ts里面必须是js代码
// 用tsc编译ts,生成js文件,就可以在浏览器运行
// 生成的文件,被修饰的入参类型将去掉
// let修饰的变量,tsc编译后变成var修饰
自动编译
1. tsc --init 生成tsconfig.json
2. tsconfig.json 内 将outDir 改成 './js'
strict 改成false
3. 终端 运行任务 tsc监视
四、类型注解
一种 “轻量级的为函数或者变量添加的约束” 的方式
typescript 提供了静态代码分析能力,它可以分析代码结构和类型注解
五、接口
一种能力,一种约束
六、类
ts的类只是一个语法题,本质还是js实现的
七、webpack+ts
八、ts基础类型
// let 变量名: 变量类型 = 值
let flag: boolean = true
console.log(flag)
boolean\number\string
undefined\null 可以作为所有类型的子类型,undefined&null可以赋值给所有子类型
let numb: number = null
数组类型
// let 变量名: 数据类型[] = [值1,值2,值3]
let arr1: number[] = [1,2,3,4]
console.log(arr1)
// 泛型 let 变量名: Array<数据类型> = [值1,值2,值3]
let arr2: Array<number> = [7,8,9]
console.log(arr2)
元组类型
let arr3: [string,number,boolean] = ['Bonnie',1.051234,false]
console.log(arr3[0].split(''))
console.log(arr3[1].toFixed(2))
枚举
// 枚举
enum Color {
red,
green=9,
blue
}
const color: Color = Color.red
console.log(color)
console.log(Color.red,Color.green,Color.blue)
console.log(Color[0],Color[9],Color[10])
enum Gender{
女,
男
}
console.log(Gender.女)
any类型
let any1: any = '~_~'
any1 = 909
console.log(any1)
let any2: any[] = [100,'小妹妹',false]
console.log(any2[1].split(''))
// console.log(any2[0].split('')) //编译不报错 浏览器报错
void类型
// void类型: 与any类型相反 代表没有任何类型
function fn():void{
console.log('小米米')
}
console.log(fn())
let vv: void = undefined
console.log(vv)
object: 非原始类型
function fnn(obj:object):object{
console.log(obj)
return {
name:'卡卡西',
age:16
}
}
console.log(fnn({}))
console.log(fnn(new String('bilibl')))
console.log(fnn(String))
联合类型,类型断言,类型推断
// 联合类型: 表示取值可以是多种类型之一
function combine(o: number|string){
// return o.toString()
if((<string>o).length){
return (o as string).length
}else {
return o.toString().length
}
}
console.log(combine(12))
console.log(combine('212'))
// 类型断言: 告诉编译器 我知道我自己在做什么
// 1. <类型>变量
// 2. 变量 as 类型
// 类型推断:TS会在没有明确的指定类型的时候推测出一个类型
// let n = 124 // => number
// n = 'aaa'
// console.log(n)
// let n // => any
// n = 123
// n = 'aaa'
// console.log(n)
九、接口
接口: 对象的状态(属性)和行为(方法)的抽象
是一种规范 一种约束 一种功能
// 需求: 创建人的对象, 需要对人的属性进行一定的约束
// id是number类型, 必须有, 只读的
// name是string类型, 必须有
// age是number类型, 必须有
// sex是string类型, 可以没有
(()=>{
interface IPerson{
readonly id:number
name:string
age:number
sex?:string
}
const person: IPerson = {
id:1,
name:'bonnie',
age:17,
sex:'女'
}
console.log(person)
})()
函数类型
// 为了使用接口表示函数类型,我们需要给接口定义一个调用签名。
// 它就像是一个只有参数列表和返回值类型的函数定义。
// 参数列表里的每个参数都需要名字和类型。
(()=>{
interface SearchFunc {
// 定义一个调用签名
(source:string, subString:string): boolean
}
const fn: SearchFunc = function (source:string, subString:string): boolean {
return source.search(subString) > -1
}
console.log(fn('我是Bonnie','我'))
})()
类类型
用接口约束类
一个类可以实现多个接口
类与类是继承(extends) 接口与类是实现(implements)
// 类类型: 用接口约束类
// 一个类可以实现多个接口
// 类与类是继承(extends) 接口与类是实现(implements)
(()=>{
interface IFly {
fly()
}
interface ISwim {
swim()
}
interface IFlyAISwim extends IFly,ISwim{}
class Person implements IFlyAISwim{
fly(){
console.log('fly')
}
swim(){
console.log('swim')
}
}
// class Person1 implements IFly,ISwim{
// fly(){
// console.log('fly')
// }
// swim(){
// console.log('swim')
// }
// }
const person = new Person()
person.fly()
person.swim()
})()
十、类
// 类: 模板 通过模板实例化对象
// 面向对象编程思想
(()=>{
// ts中类的定义
class Person {
// 属性
name: string
age: number
gender: string
// 构造方法: 初始化对象属性
constructor(name: string='Bonnie',age: number=18,gender: string='girl'){
this.name = name
this.age = age
this.gender = gender
}
// 实例方法
sayHi(str: string) {
console.log(`my name is ${this.name},i'm ${this.age} & i'm a ${this.gender},${str}`)
}
}
const person = new Person()
person.sayHi('马萨赛季')
})()
继承
// 类与类之间的继承关系
// A继承了B
// A => 子类 -> 派生类
// B => 基类 -> 超类(父类)
// 继承用extends
// 子类用super继承父类的构造器,属性,方法
// 子类可以重写父类
(()=> {
class Person {
name: string
age: number
constructor(name:string='人', age:number=0){
this.name = name
this.age = age
}
sayHi(str: string){
console.log(`哇哇哇,${str},我是${this.name}`)
}
}
class Student extends Person{
constructor(name:string, age:number) {
super(name,age)
}
// 重写
sayHi() {
console.log('i"m student')
super.sayHi('嘟嘟嘟')
}
}
const person = new Person()
console.log(person)
person.sayHi('ccc')
const stu = new Student('Bonnie',16)
console.log(stu)
stu.sayHi()
})()
多态
父类的引用指向子类的对象 不同类型的对象针对相同方法,产生不同的行为
(()=>{
class Animal {
name: string
constructor(name: string){
this.name = name
}
run(distance:number=0){
console.log(`${this.name}跑了${distance}米`)
}
}
class Dog extends Animal{
constructor(name: string){
super(name)
}
run(distance:number=5){
console.log(`${this.name}跑了${distance}米`)
}
}
class Pig extends Animal {
constructor(name: string){
super(name)
}
run(distance:number=10){
console.log(`${this.name}跑了${distance}米`)
}
}
const ani: Animal = new Animal('动物')
const dog: Animal = new Dog('狗')
const pig: Animal = new Pig('猪')
ani.run()
dog.run()
pig.run()
const dog1: Animal = new Dog('gou')
const pig1: Animal = new Pig('zhu')
dog1.run()
pig1.run()
function showRun(ani: Animal){
ani.run()
}
console.log('==========')
showRun(dog1)
showRun(pig1)
})()
修饰符
// 修饰符:修饰类内部属性成员的可访问性
// 类的属性方法构造器 默认用public修饰
// public -- 公共类 修饰的成员 任何位置都能访问
// private -- 私有类 修饰的成员 在类外部不能访问, 子类也无法访问
// protected -- 受保护类 修饰的成员 在类外部不能访问, 子类可访问
(()=>{
class Person {
public name: string
// private name: string
// protected name: string
public constructor(name: string){
this.name = name
}
public eat(){
console.log(this.name,'eat')
}
}
class Stu extends Person{
constructor(name: string){
super(name)
}
public eat(){
console.log(this.name,'eat')
}
}
const person = new Person('bonnie')
console.log(person.name)
person.eat()
const stu = new Stu('andy')
console.log(stu.name)
})()
readonly修饰符
// readonly修饰符: readonly修饰的属性成员,在外部无法修改,只可读;
// 在类内部的普通函数也无法修改;只能在构造函数内部进行赋值
(()=>{
// class Person {
// readonly name: string = 'moren'
// constructor(name:string){
// this.name = name
// }
// changeName(){
// this.name = 'xxx'
// }
// }
// const p1 = new Person('bonnie')
// p1.name = 'ccc'
// console.log(p1.name)
// readonly修饰构造器的参数,该类就有了一个只读的属性成员,外部可访问但无法修改
// 使用public private protected修饰构造器的参数,该类就有了一个或公共或私有或受保护的属性成员
class Person {
constructor(public name:string){
this.name = name
}
}
const p1 = new Person('bonnie')
p1.name = 'ccc'
console.log(p1.name)
})()
存取器
存取器:在类中,对类中的属性进行有效的控制 通过getter setter进行实现
(()=>{
class Person {
firstName: string
lastName: string
constructor(firstName:string, lastName:string){
this.firstName = firstName
this.lastName = lastName
}
get fullName(){
console.log('get....')
return this.firstName+'_'+this.lastName
}
set fullName(val){
console.log('set....',val)
const n = val.split('_')
this.firstName = n[0]
this.lastName = n[1]
}
}
const p = new Person('上官','婉儿')
console.log(p.fullName)
p.fullName = '薛_宝钗'
console.log(p.fullName)
})()
静态成员
// 静态成员: 用static修饰的类的属性或者方法
// 静态成员 不能通过实例对象访问 需要通过 类.静态属性 进行访问
// 静态方法 需要通过 类.静态方法 进行访问
(()=>{
class Person {
// static name 报错 静态属性“name”与构造函数“Person”的内置属性函数“name”冲突。
static name1: string = '贾宝玉'
constructor() {
// this.name1 = name1
}
static say(){
console.log('i"m ',Person.name1)
}
}
const p = new Person()
console.log(p)
// p.say()
// console.log( p.name1)
// console.log(Person.name1)
Person.say()
})()
抽象类
// 抽象类:abstract 包含抽象方法(一般没有任何功能的具体实现)不能实例化抽象类 只能给子类实例化和让子类实现内部的抽象方法
// 抽象类服务于派生类
(()=>{
abstract class Animal {
abstract eat()
// 报错 astract标记的抽象类,不能有代码的实现
// abstract eat(){}
sayHi(){
console.log('hi')
}
}
// 不能实例化抽象类
// const dog = new Animal()
class Dog extends Animal {
eat() {
console.log('汪汪 骨头')
}
}
const dog = new Dog()
dog.eat() // 抽象类的实现
dog.sayHi() //调用抽象类的实例方法
})()
十一、函数
// 函数: 重复代码的整合 功能的实现
(()=>{
// 函数声明 命名函数
function add(x: string, y: string): string {
return x+y
}
// 函数表达式 匿名函数
let add2 = function (x: number, y: number): number {
return x+y
}
console.log(add('a','b'))
console.log(add2(1,2))
// ts函数完整写法
let add3:(x: number, y: number)=> number = function (x: number, y: number): number {
return x+y
}
console.log(add2(99,88))
})()
默认参数、可选参数
// 默认参数 若不传,默认某个值
// 可选参数 ?修饰的参数 可传可不传
(()=>{
function showName(firstName:string='贾',lastName?:string){
return firstName+'_'+lastName
}
console.log(showName('雪','抱柴'))
})()
剩余参数
// 剩余参数(rest参数)
// 在函数声明的时候,只能放在所有参数的最后
(()=>{
function add (n1: number,n2: number,...ns:number[]): void{
console.log(n1)
console.log(n2)
console.log(ns)
}
add(1,2,3,4,5,5)
})()
函数重载声明
// 函数重载 名字相同 参数返回值不同
(()=>{
// 函数重载声明
function add(x:number,y:number): number
function add(x:string,y:string): string
function add(x:number|string,y:number|string){
if(typeof x === 'number' && typeof y === 'number')
return x+y
else if (typeof x === 'string' && typeof y === 'string')
return x+y
}
console.log(add(1,4))
console.log(add('1','4'))
// console.log(add(1,'4'))
// console.log(add('1',4))
})()
十二、泛型
泛型:在定义函数、接口、类时不确定使用的数据类型,只有在使用函数、接口、类时才确定
// 泛型:在定义函数、接口、类时不确定使用的数据类型,只有在使用函数、接口、类时才确定
(()=>{
// const getArr = <T>(value:T, num:number):T[]=>{
// const arr: T[] = new Array(num).fill(value)
// return arr
// }
function getArr<T>(value:T, num:number):T[]{
const arr: T[] = new Array(num).fill(value)
return arr
}
console.log(getArr<number>(123,3))
console.log(getArr<string>('ccc',8))
})()
多个泛型参数的函数
(() => {
function getMsg<K, V>(value1: K, value2: V): [K, V] {
return [value1, value2];
}
const arr = getMsg<string,number>('abc',21.121)
console.log(arr[0].split(''),arr[1].toFixed(1))
})();
泛型接口
在定义接口时,为属性或方法指定泛型类型,在使用时,才确定具体的泛型类型
(()=>{
interface IBaseCRUD<T> {
data: Array<T>
add:(user: T) => T
getUserById:(id: number) => T
}
class User {
id?: number
name: string
age: number
constructor(name:string,age:number){
this.name = name
this.age = age
}
}
class UserCRUD implements IBaseCRUD<User>{
data: Array<User> = []
add(user: User):User{
user.id = Date.now()+Math.random()
this.data.push(user)
return user
}
getUserById(id: number): User{
return this.data.find(e=>e.id===id)
}
}
const ucrud = new UserCRUD()
ucrud.add(new User('andy',1))
ucrud.add(new User('bonnie',12))
ucrud.add(new User('kitty',31))
console.log(ucrud.data)
const {id} = ucrud.add(new User('billy',2))
const u1 = ucrud.getUserById(id)
console.log(u1)
})()
泛型类
泛型类: 定义一个类,传参、属性与返回值是泛型
(()=>{
class Generic<T>{
defaultValue: T
add:(x:T, y:T) => T
}
const g1:Generic<string> = new Generic<string>()
g1.defaultValue = 'Bonnie'
g1.add = (x:string, y:string):string => {
return x+'_'+y
}
console.log(g1.add('史','湘云'))
console.log(g1.add(g1.defaultValue,'湘云'))
const g2:Generic<number> = new Generic<number>()
g2.defaultValue = 99
g2.add = (x:number, y:number):number => {
return x+y
}
console.log(g2.add(1,2))
console.log(g2.add(g2.defaultValue,3))
})()
泛型约束
如果我们对泛型参数取length属性,会报错,因为泛型不知道它有这个属性
(()=>{
interface ILen{
length:number
}
function getLen<T extends ILen>(x:T):void{
console.log(x.length)
}
getLen<string>('abcd')
// getLen<number>(12)
})()
十三、其他
声明文件
/*
当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
声明语句: 如果需要ts对新的语法进行检查, 需要要加载了对应的类型说明代码
declare var jQuery: (selector: string) => any;
声明文件: 把声明语句放到一个单独的文件(jQuery.d.ts)中, ts会自动解析到项目中所有声明文件
下载声明文件: npm install @types/jquery --save-dev
*/
//手动声明
import jQuery from 'jquery'
// 定义声明文件 (或者放到jQuery.d.ts文件里(自建))
declare var jQuery:(selector: string)=>any
jQuery('选择器')
内置对象
(()=>{
/* 1. ECMAScript 的内置对象 */
// Boolean
// Number
// String
// Date
// RegExp
// Error
let b: Boolean = new Boolean(1)
let n: Number = new Number(true)
let s: String = new String('abc')
let d: Date = new Date()
let r: RegExp = /^1/
let e: Error = new Error('error message')
// b = true
console.log(b)
// let bb: boolean = new Boolean(2) // error
// 2. BOM 和 DOM 的内置对象
// Window
// Document
// HTMLElement
// DocumentFragment
// Event
// NodeList
const div: HTMLElement = document.getElementById('test')
const divs: NodeList = document.querySelectorAll('div')
document.addEventListener('click', (event: MouseEvent) => {
console.dir(event.target)
})
const fragment: DocumentFragment = document.createDocumentFragment()
console.log(div,divs,fragment)
})()