typeScript 个人学习

132 阅读9分钟

1、安装编译软件让其支持typescript

1-1、安装 typescript

npm install -g typescript 或: yarn global add typescript

1-2、创建文件夹,在vscode中输入

tsc --init

image.png

image.png

1-3、配置输出文件

image.png

1-4、配置vscode终端监视typescript自动生成js

image.png

image.png

1-5 创建ts 文件即可实现

image.png

2、Ts 数据类型的定义

2-1 基本数据类型

// 定义字符串类型
let str:string = 'ts'
// 定义boolean类型
let falg:boolean = true 
// 定义number类型
let num:number = 10 
// 定义null
let isNull:null = null
// 定义undefined
let isUndefined:undefined = undefined
let num:number | undefined // 用于并未赋值的数值类型
// 定义any类型
let isAny:any = [] // 任意类型好比关闭了该变量的ts类型,使用js【常用于无法确定具体规定的类型,例如DOM节点的获取】

2-1-1 联合数据类型

只能访问此联合类型的所有类型里共有的属性或方法

联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型

// 定义联合类型
let params:string|number
// 只能访问此联合类型的所有类型里共有的属性或方法
function getLength(something: string | number): number {
    return something.length; // 错误
} 

2-1-2 类型别名【type】

type typeList = string | number | number[]

const b:typeList = [1,2,34,0]

2-1-3 常用内置对象定义

// 内置对象: 常用:【Date/RegExp/HTMLElement/NodeList/MouseEvent】
let date:Date = new Date()
let math:RegExp = /\s/g
const body: HTMLElement = document.body;
const divList: NodeList = document.querySelectorAll('div');
document.addEventListener('click', (e: MouseEvent) => {})

2-2 复合数据类型

2-2-1 数组定义

let arr:number[] = [1,25,6]
let arr2:Array<number> = [1,2,5]
let arr3:[string,number] = ['xxx',10] // 元祖类型

2-2-2 枚举类型

参考文档

enum flag {color = 1 ,red = 2}
console.log(flag.color) // 1
console.log(flag[1]) // color

enum flag2 {color,red}
console.log(flag2.color) // 0

enum flag3 {color,red = 10,yellow,block = 11}

console.log(flag3.color,flag3.red,flag3.yellow,flag3.block,flag3[11]) // 0 10 11 11 block
// 原因:枚举类型的编译结果及输出的枚举结果
// 编译结果
var flag3;
(function (flag3) {
    flag3[flag3["color"] = 0] = "color";
    flag3[flag3["red"] = 10] = "red";
    flag3[flag3["yellow"] = 11] = "yellow";
    flag3[flag3["block"] = 11] = "block";
})(flag3 || (flag3 = {}));


console.log(flag3) 

{
  0: 'color',
  10: 'red',
  11: 'block',
  color: 0,
  red: 10,
  yellow: 11,
  block: 11
}

2-2-3 void 类型

//  用于定义函数无返回值
function run():void{
    console.log('void类型')
}
// !!! 错误写法
function run():undefined{
    console.log('void类型')
}

3、Ts 函数的定义

3-1-1、规定参数类型【必传】

function funTs(name:string,age:number):string{  // 定义函数的参数类型和返回值类型
    return name + age
}
funTs('n')【错误】 // 以上方法定义的参数在ts中参数都为必传且符合规定类型

3-1-2、可选参数【只能配置在参数末尾】

function funTs(name:string,age?:number):string{  // 定义函数的参数类型和返回值类型
    return name + age
}
funTs('xx') // 正确

3-1-3、默认参数

function funTs(name:string = '小明',age:number):string{  // 定义函数的参数类型和返回值类型
    return name + age
}
funTs('xx',10) // 正确

3-1-4、剩余参数

function funTs(name:string = '小明',age:number,...rest:number[]):string{  // 定义函数的参数类型和返回值类型
    return name + age
}
funTs('xx',10,10,345) // 正确

3-1-5、函数的重载

重载允许一个函数接受不同数量或类型的参数时,作出不同的处理。

// 不使用函数重置,该函数返回值类型是仍然是 :  string | number
function get(params:string | number):string | number { // 儿子一和儿子二商量着来,父亲无法确定谁来照顾他
    if(params) {
        return 10
    }
    return 'xxx'
}
let result1:string = get('xxx') // 错误
let result2:number = get (10) // 错误
// 使用函数重载可以确定函数唯一返回值类型
function get2(params:string):string // 儿子一为 String
function get2(params:number):number // 儿子二为 number
function get2(params:string | number):string | number { // 父亲可以确定哪个儿子来照顾他
    if(params) {
        return 10
    }
    return 'xxx'
}
let res1:string = get2('xxxx')
let res2:number = get2(10)

4.interface【接口】

使用接口(Interfaces)来定义对象的类型

接口好比一个模具提前规定了某些对象的样子(属性特征),所以赋值的时候,变量的形状必须和接口的形状保持一致。

// 基本语法
interfaces 接口名 {
    接口的定义
}
// 基本使用
// 定义 userInfo 的接口类型
interface IUserInfo {
    age:number,
    like?:Array<string>
}
// 定义 queryParams 的接口类型
interface IQueryParams {
    userId:number,
    userName:string,
    userInfo:IUserInfo,
}
// 使用接口
let formData:IQueryParams = {
    userId:10,
    userName:'person',
    userInfo:{
        age:20,
        like:['电影']
    }
}

4-1-1 定义接口任意属性和只读属性【readonly】

一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集

只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候

interface IUserInfo {
    name:string,
    age:number,
}
const obj:IUserInfo = {
    name:'xx',
    age:10,
    score:10, // 错误
}
// 定义任意类型【】
interface IUserInfo {
    name:string,
    age:number,
    [attribute:string]:string | number, // 任意属性的类型是接口确定属性类型的集合,一般设置成 any 类型
}
const obj:IUserInfo = {
    name:'xx',
    age:10,
    score:10,
    class:'一'
}

// 定义任意类型方法二【无需在接口中设置任意类型】
interface IUserInfo {
    name:string,
    age:number,
}

let score:string = 'test'

const obj:IUserInfo = {
    name:'xx',
    age:10,
    [score]:[1,2131]
}
// 定义任意属性
interface IUserInfo {
   readonly name:string,
    age:number,
}
const obj:IUserInfo = {
    name:'yellow',
    age:20
}
obj.name = 'xxx' // 错误【不可修改改属性值】

4-1-2 利用接口定义函数的形状

// 定义函数模型【函数参数1 为 string 类型 参数2 为 string  返回值为 string】
interface IFunDesc {
    (name:string,color:string):string 
}
// getIfo 使用定义的函数模型
let getInfo:IFunDesc
// 根据模型创建函数
 getInfo = (params:string,params2:string):string => {
    return params + params2
}

4-1-3 接口的继承

interface IMac {
    color:string,
}
interface IMacBook extends IMac {
    get(params:string):void
}
const a:IMacBook = {
    color:'red',
    get(params:string){
        console.log(params)
    }
}
a.get('xxxx')
a.color

4-1-4 类类型接口【implements】

interface IPerson { // 规定使用该接口的类必须用接口中的方法和属性
    name:string,
    age:number,
    say(context:string):void
}

class Person implements IPerson { // implements 使用 类接口
    name:string
    age:number
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
    say(context:string){
        console.log(context)
    }
}

5. class

5-1-1 实现类的简单继承

继承必要条件:父子都要有constructor构造器(父类不写默认条件),子类必须写constructor构造器且使用 super() 方法借用父类的属性。【此处指的都是公有方法和属性】

class Person {
  name:string = '父类'
  constructor(){  // 每次实例化对象其实就是调当前constructor方法
                              
      }
} 

class Son extends Person {
    constructor(){
        super() // super 相当于当前类的父类(父类的constructor方法)
    }
    say(){
        console.log(`访问父类的:${this.name}`)
    }
}
const Baba = new Person()
console.log(Baba.name) // 父亲
const a = new Son()
a.say() // 访问父类的:父亲


// 使用  abstract 关键字 实现抽象类和方法【不能被实例的类】
 abstract class Person {
    public age:number | undefined
    constructor(age:number){
        this.age = age
    }
   abstract say():void
}

5-1-2 设置公有属性【public】【父类、子类、子类和父类实例对象都可访问】

class Person {
  public name:string = '父类' // 公有属性public 可省略
} 

class Son extends Person {
    constructor(){
        super() 
    }
    say(){
        console.log(`访问父类的:${this.name}`)
    }
}
const Baba = new Person()
console.log(Baba.name) // 父亲
const a = new Son()
a.say() // 访问父类的:父亲

5-1-3 设置保护类属性【protected】【父类、子类中可以访问】

class Person {
  protected name:string = '父类'
} 

class Son extends Person {
    constructor(){
        super()
    }
    say(){
        console.log(`访问父类的:${this.name}`)
    }
}
const Baba = new Person()
console.log(Baba.name) // 不可访问
const a = new Son()
a.say() // 访问父类的:父亲【子类方法中,在子类中访问父类属性】

5-1-4 设置私有属性【private】 【只有父类中可以访问】

class Person {
  private name:string = '父类'
  say(){
      console.log('父类:',this.name)
  }
} 

class Son extends Person {
    constructor(){
        super()
    }
    say(){
        console.log(`访问父类的:${this.name}`) // 报错,不可访问父类的属性
    }
}
console.log(Person.name) // 父亲
const Baba = new Person()
console.log(Baba.name) // 不可访问
Baba.say() // 父类:父亲 【父类方法中访问父类的属性】

5-1-5 设置静态方法【static】

class Person {
  static say(){
      console.log('父类:',this.name)
  }
} 

class Son extends Person {
    constructor(){
        super()
    }
}
Person.say()  // 可以访问
const a = new Person()
a.say() // 不可访问

6.元祖

数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。可以让数组设置不同的item类型

let arr:[string,number] = ['xxx',10]
arr.push('sstr') // 可以越界添加元素,但是类型是其元祖类型中类型的复合

7.泛型

参考博客

是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。相当与对any类型的升级版,它会根据用户输入的具体类型来进行断言【解决类、函数、方法的复用性并且兼容不定类型的数据】

7-1-1 函数中泛型的使用

T 是类型变量[可以使用任何字母代替,常用 T/U ],它是一种特殊的变量,只用于表示类型而不是值,使用 <> 定义。定义了类型变量之后,你在函数中任何需要指定类型的地方使用 T 都代表这一种类型,这样也能保证返回值的类型与传入参数的类型是相同的了。

  // 不适用泛型时的书写方法
function get(params:string):string
function get(params:number):number
function get(params:string | number):string | number | undefined{
    if(params as string) {
        return 'xxx'
    }else if(params as number) {
        return 6666
    }
}
get('xxx') 
get(10)
// 使用泛型
function get<T>(params:T):T{
    return params
}

get<number>(10)
get<string>('xxx')

7-1-2 泛型接口

interface IParams<T>{ // 定义泛型参数为 T 
    name:string,
    age:number,
    test:T
}
const obj:IParams<string>= { // 使用泛型时要给定其泛型参数类型
    name:'xxx',
    age:10,
    test:'xxxx'
} 

// 方法一
interface IPer<T> {
    (params:T):T
}

let result:IPer<string> = function getReust<T>(params:T):T{ 
    return params
}
result('xxxx')
// 方法二
let result2:IPer<number> = <T>(params:T):T => params
result2(10)
// 方法三
let result3 = <T>(params:T) => params 
result3<number>(20)

7-1-3 泛型的约束【约束好泛型拥有的属性】

const resulut = <T>(params:T) => params.length // 类型“T”上不存在属性“length”【报错】

// 泛型的约束
interface Ileng {  // 约定泛型可拥有的属性
    length:number
}
const resulut = <T extends Ileng>(params:T) => params.length 

image.png

7-1-4 类泛型使用

class Per<T>{
    params:T
    constructor(params:T){
        this.params = params
    }
}
const a = new Per<number>(10)
const a2 = new Per<string>('xxx')

7-1-5 类型泛型和接口的使用

class Handler<T>{
    say(params:T):T{
        return params
    }
}

interface Ipara {
    name:string
}

const a = new Handler<Ipara>()
a.say({name:'xxcvxv'})
a.say({name:10}) // 错误
========================================
class Handler<T>{
    name:string
    constructor(params:string){
        this.name = params
    }
    say(params:T):T{
        return params
    }
}

interface Ipara {
    name:string
}

const a = new Handler<Ipara>('熊')
a.say({name:'xxcvxv'}) // 'xxcvxv'
a.name // '熊'
a.say({name:10}) // 错误

8.命名空间【namespace】

开启一块属于自己的私人空间,开启命名空间,外部要用改空间中的数据,需要利用export 暴露

//  共公模块
export namespace Project {  // 命名空间1
  export interface IObj {
        name:string
    }
}

export namespace Project2 {  // 命名空间2
   export interface IObj {
        age:number
    }
}
// 使用模块
import {Project,Project2} from './a'
let obj:Project.IObj = {
    name:'xxx'
}
let obj2:Project2.IObj = {
    age:10
}

9. 装饰器

本质是一个方法,可以为类、方法、属性进行扩展,不能修改当前的类。

9-1-1类修饰器

// 不修改改变当前类,只能在其当前类的prototype上添加属性或方法

// =================== 一般修饰器 =============================
function PerSonDec(target:any){ // 收到当前被修式的类
    target.prototype.color = 'xxx'
    target.prototype.run = function () {
        console.log('run')
    }
}

@PerSonDec // 被修饰的类前书写 @修饰器名称
class Person {
    public age:number | undefined
    constructor(age:number){
        this.age = age
    }
    say(){

    }
}

const son = new Person(200)
console.log(son)
// Person {age: 200}
//     age: 200
//         [[Prototype]]: Object
//             color: "xxx"
//             run: ƒ ()
//             constructor: class Person
//             say: ƒ say()
//             [[Prototype]]: Object

// ================= 工厂方式装饰器【看动态传参】 ========================
function PerSonDec(color:string){ 
    return function(target:any){
        target.prototype.color = color

    }
}

@PerSonDec('red') // 被修饰的类前书写 @修饰器名称
class Person {
    public age:number | undefined
    constructor(age:number){
        this.age = age
    }
    say(){

    }
}

9-1-2 修饰器实现对当前类的重载

function PerSonDec(target:any){ 
    return class newPersonClass extends target {
        age:number = 200
        say(){
            
        }

    }
}

@PerSonDec 
class Person {
    public age:number | undefined
    constructor(age:number){
        this.age = age
    }
    say(){

    }
}

const son = new Person(200)
console.log(son)

9-1-3 类的属性装饰器

function PerSonAttrDec(params:string){ 
    return function(target:any,attr:any){ // target: 当前类的 prototype , arrt : 被修饰的属性
        target[attr] = '原型对象上的属性' 

    }
}
class Person {
   @PerSonAttrDec('xxx')
    age:number = 20
    constructor(){

    }
    say(){
    }
}
const son = new Person() 
console.log(Person.prototype.age) // 原型对象上的属性
console.log(son.age)//20

9-1-4 类的方法修饰器

function PerSonFunDec(params:string){ 
    return function(target:any,funName:string,dec:any){  // target: 当前类的显示原型对象  funName : 被修饰的方法名 dec:修饰器对修
        console.log(dec.value) // 当前被修饰的方法
        dec.value = function(){
            console.log('修饰器修改了我')
        }

    }
}
class Person {
    age:number = 20
    constructor(){

    }
    @PerSonFunDec('xxx')
    say(){
        console.log('wo')
    }
}
const son = new Person() 
son.say() // 修饰器修改了我

9-1-5 类方法参数修饰器

function ParamsDec(params:string){ 
    return function(target:any,funName:string,paramsIndex:number,){  // target: 当前类的显示原型对象  funName : 被修饰的方法名 paramsIndex:被修饰参数的索引

    }
}
class Person {
    age:number = 20
    constructor(){

    }
    
    say(@ParamsDec('xxxx') color:string){
        console.log(color)
    }
}
const son = new Person()