TS 从 0 到 1,通熟易懂

学习TS的原因?

一方面,顺应潮流,最近校招面试的大公司都陆续问道是否会 TypeScript,由于之前在滴滴都是使用的 React+JS,所以现在决定把 TS 学了,以备不时之需。另一方面,前端程序员确实比较缺乏面向对象的思想,继承、泛型、强类型之类的,就大学学了,用得寥寥,乘此机会也加强一下自己这方面的基础。

安装 typescripts 与自动编译 TS 文件

cnpm install typescript -g

配置好环境变量后重新打开终端看 ts 是否安装成功,版本号出来代表已成功
在这里插入图片描述
编译 .ts 文件报错:
tsc : 无法加载文件 E:\小伍的文件\node安装文件夹\node_global\tsc.ps1
在这里插入图片描述
解决
查看 shell 中的执行策略:

get-ExecutionPolicy

我的是:Restricted
更新执行策略:

Set-ExecutionPolicy -Scope CurrentUser

手动输入:RemoteSigned 即可
再执行 tsc index.ts 就能将 ts 文件成功编译成 es5 的 index.js,这样浏览器才会认识
但是目前每次编写 ts 代码都需要手动编译成 es5 代码比较麻烦,所以我们来开启 tsc 监视
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
生成 tsconfig.json 配置文件
在这里插入图片描述
修改配置文件中的输出文件夹:
在这里插入图片描述
每次当我们修改 ts 代码都能实时编译出 es5 代码了,index.js 文件就放在名为 js 文件夹下
在这里插入图片描述

TS 中的数据类型

作用:使代码更规范、更有利于维护
Number、String、Boolean、Null、undefined、Array、tuple(元组类型)、enum(枚举类型)、any(任意类型)、void 类型、never(其它类型)

let str: string = '你好 ts'
let num: number = 123
let a: any = 789
str = 123 // 报错,因为 str 是字符串类型,不能被赋值为数字类型
let arr: number[] = [1, 2, 3, 4, 5]  // 定义一个只能放数字的数组
let arr1:Array<string> = ['a', 'b', 'c'] // 数组指定一种类型

// 元组类型,可以指定数组的多种类型
let arr:[string, boolean, number] = ['abs', true, 145] 

 // 枚举类型
enum Flag {
    
     success = 1, error = 0 }
let isF:Flag = Flag.success  // 1
enum frult {
    
     apple, pear, banana}
let f:frult = frult.apple // 1 不赋值就是索引的值 

// any(任意类型)的用处:当获取 DOM 节点时,我们或许会改变 DOM 节点的样式,这时我们 .style 时就会报错,就需要赋值any类型
let oBox:any = document.getElementById('box') // 这里不指定any就会报错
oBox.style.color = 'red'

// null、undefined是其它类型(never)的子类型
let num:undefined  // 打印输出undefined,正确,否则定义不赋值就会报错
let num:number | undefined

TS中的方法(函数)

// void 标识这个方法没有返回值
function go(): void {
    
     
    console.log('no back')
}

// 函数返回数字
function sum(): number{
    
    
	return 123
}

// 匿名函数
let fun = function ():number{
    
    
	return 456
}

// 规定参数类型
function getInfo(name: string, age: number): string {
    
    
    return `${
      
      name}---${
      
      age}`
}
getInfo('李四', 18) // 李四---18

方法的可选参数

上面的函数,必须要传两个参数,如果我们只想传 name 不想传 age,就在 age 处打 ?

function getInfo(name: string, age?: number): string {
    
    
	...
}

方法的默认参数

ES5 中无法设置默认参数,ES6 和 TS 皆可设置,设置了默认参数后,参数可传也可不传

function getInfo(name?: string, age: number = 20): string {
    
    
    return `${
      
      name}---${
      
      age}`
}
getInfo('李四')   // 李四---20

方法的剩余参数

function getSum(...res: number[]): number {
    
    
    let sum = 0
    res.map(item => sum += item)
    return sum
}
getSum(1, 2, 3, 4) // 10

ts函数重载

定义多个重名方法,前面的方法都没有方法体,最后一个方法参数 any,返回值 any 内部做判断返回具体的值

function getSomething(name:string):string;
function getSomething(name:number):string;
function getSomething(name:any):any{
    
    
    if(typeof name == 'string'){
    
    
        return  `我是${
      
      name}`
    }
    else{
    
    
        return  `年龄透明——${
      
      name}`
    }
}
getSomething('张三'); // 我是张三
getSomething(true); // 编译不通过

// 也可以传两个参数
function getSomething(name:string):string;
function getSomething(name:string, age:number):string;
function getSomething(name:any, age?:any):any{
    
     // 最后一个函数都是 any
	if(age){
    
    
		return  `我是${
      
      name}年龄${
      
      age}`
	}
	else{
    
    
		return  `我是${
      
      name}`
	}
};

TS 中的类

class Person {
    
    
    name: string;
    constructor(name: string) {
    
    
        this.name = name
    }
    getName(): string {
    
    
        return `${
      
      this.name}`
    }
    setName(name: string): void {
    
    
        this.name = name
    }
}

let p = new Person('张三')
p.getName()// 张三
p.setName('王五')
p.getName(); // 王五

TS 中实现继承

class Animal {
    
    
    name: string;
    constructor(name: string) {
    
    
        this.name = name
    }

    cry(): string {
    
    
        return `${
      
      this.name}会咆哮`
    }
}

let a = new Animal('tiger')
console.log(a.cry()); // tiger 会咆哮

class Loin extends Animal{
    
    
    constructor(name:string){
    
    
        super(name)
    }

    king():string{
    
    
        return  `${
      
      this.name}是丛林之王`
    }
}

let l = new Loin('狮子')
console.log(l.king()); // 狮子是丛林之王
console.log(l.cry()); // 狮子会咆哮

TS 类中的三种修饰符

TS类中的三种修饰符

TS 中的静态方法

静态方法无法使用类中的非静态属性

class Animal {
    
    
    name: string;
    static age:number = 5 // 静态属性
    constructor(name: string) {
    
    
        this.name = name
    }

    cry(): string {
    
    
        return `${
      
      this.name}会咆哮`
    }

	static getAge():number{
    
     // 静态方法
		// return ${this.name} 报错,因为静态方法无法使用类中的非静态属性
		return 	Animal.age
	}
}

TS 中的多态

1、父类定义一个方法,但不去实现
2、让继承它的子类去实现,每一个子类有不同的实现,但不是一定要去实现,换个意思说,也可以不去实现;
3、多态属于继承

class Animal {
    
    
    name: string;
    constructor(name: string) {
    
    
        this.name = name
    }

    cry(): string {
    
    
        return `${
      
      this.name}会咆哮`
    }

    eat(){
    
     // 父类定义了方法但不实现,因为它的子类很多,父类也不知道要具体实现什么

    }
}

class Loin extends Animal{
    
    
    constructor(name:string){
    
    
        super(name)
    }

    king():string{
    
    
        return  `${
      
      this.name}是丛林之王`
    }

    eat():string{
    
     // 子类实现父类的方法,各个子类中有不同的实现方式
        return  `${
      
      this.name}吃肉`
    }
}

class Cow extends Animal{
    
    
    constructor(name:string){
    
    
        super(name)
    }

    eat():string{
    
     // 子类实现父类的方法,各个子类中有不同的实现方式
        return  `${
      
      this.name}吃青草`
    }
}

let l = new Loin('狮子')
let c = new Cow('牛')
console.log(l.eat()); // 狮子吃肉
console.log(c.eat()); // 牛吃青草

用 abstract 修饰的抽象类和抽象方法

规定
1、抽象类(用 abstract 修饰的类)中的抽象方法不包含具体的实现,并且必须在派生类中实现。
2、抽象方法必须包含在抽象类中,要求派生类中必须包含这个方法(不然报错),当然抽象类中还可以写其它的普通属性和方法
3、抽象类提供其它类继承的基类,它自身不能被实例化。

abstract class Animal {
    
    
    name: string; // 抽象类中的正常属性
    constructor(name: string) {
    
    
        this.name = name
    }

    cry(): string {
    
     // 抽象类中的正常方法
        return `${
      
      this.name}会咆哮`
    }

   abstract eat():any // 抽象类中类定义了抽象方法,但不能有方法体
}

let a = new Animal() // 报错,因为无法创建抽象类的实例

class Loin extends Animal{
    
     // 子类继承抽象父类,必须实现父类中的抽象方法
    constructor(name:string){
    
    
        super(name)
    }

    king():string{
    
    
        return  `${
      
      this.name}是丛林之王`
    }

    eat():string{
    
     // 子类继承抽象父类,必须实现父类中的抽象方法
        return  `${
      
      this.name}吃肉`
    }
}

class Cow extends Animal{
    
    
    constructor(name:string){
    
    
        super(name)
    }

    eat():string{
    
      // 子类继承抽象父类,必须实现父类中的抽象方法
        return  `${
      
      this.name}吃青草`
    }
}

let l = new Loin('狮子')
let c = new Cow('牛')
console.log(l.eat()); // 狮子吃肉
console.log(c.eat()); // 牛吃青草

TS 中的接口 interface

接口作用:接口起到限制和规范的作用

属性接口(用得较多)

对 json 的约束,也就是对方法的传入参数进行约束

interface Person{
    
     // 属性接口定义了必须传入 name、age 的规范,sex 属于可选参数,可传可不传
    name: string;
    age: number;
    sex?: string;
}

function getInfo(info:Person){
    
     
    return  `${
      
      info.name}--${
      
      info.age}`
}

console.log(getInfo({
    
    name:'张三',age:22})); // 传入函数的参数必须包含 name、age,少传其中一个就会报错

函数类型接口

实现接口的函数,必须满足接口的格式:两个参数必须有,并且类型一致,函数返回值必须是 string 类型

interface getInfoFn {
    
     (value: string, value2: number): string }

let getInfo: getInfoFn = function (name: string, age: number): string {
    
    
    return `我叫${
      
      name},今年${
      
      age}`
}

getInfo('张三', 18); // 我叫张三,今年 18 岁
getInfo(123, 18); // 报错,123 不是 string 类型

类类型接口

对类的约束,和抽象类类似,父类接口中规定的属性和接口,在子类中必须要有

interface Person{
    
     // 类接口规定了子类必须要有 name 属性和 say 方法
    name: string;
    say(): void;
}

class Chind implements Person{
    
     // 用 implements 表示 Child 类要实现 Person 这个接口
    name: string;
    
    constructor(name: string) {
    
    
        this.name = name
    }

    say() {
    
    
        console.log(`${
      
      this.name}很漂亮`);
    }
}

let c = new Chind('小白')
console.log(c.say()); // 小白很漂亮

接口扩展:接口可以继承接口

interface Person{
    
     // 类接口规定了子类必须要有 name 属性和 say 方法
    name: string;
    say(): void;
}

interface YellowPerson extends Person{
    
     // YellowPerson 类接口继承了 Person 接口,规定了子类必须要有 name 属性,say、eat 方法
    eat():string;
}

class Chind implements YellowPerson{
    
     // 用 implements 表示 Child 类要实现 YellowPerson 这个接口
    name:string;
    
    constructor(name:string){
    
    
        this.name = name
    }

    say(){
    
    
        console.log(`${
      
      this.name}很漂亮`);
    }

    eat(){
    
    
        return `${
      
      this.name}爱吃肉`;
    }
}

let c = new Chind('小黄')  
console.log(c.say()); // 小黄很漂亮
console.log(c.eat()); // 小黄爱吃肉

TS 中的泛型

可以使用泛型来创建可重用的组件,这样一个组件可以支持多种数据类型
如果我们要求一个函数可以返回 string 类型、同时也可以返回 number 类型,那么用 any 可以解决这个问题:

function getInfo(value: any): any {
    
    
    return value
}

getInfo('张三'); // 张三
getInfo(18); // 18

以上写法缺点:any 相当于放弃了类型检查,也就是我传入 number 类型,但是它仍然可以返回 string 数据类型

泛型函数

可以支持不特定的数据类型,函数具体返回什么数据类型由传入的参数决定,并且它们始终能保持一致,对不特定数据类型支持
要求:传入的参数和返回的参数一致

function getInfo<T>(value:T): T {
    
     // 泛型定义
    return value
}

getInfo<string>('张三'); // 泛型函数
getInfo<string>(18); // 报错,因为传入的参数数据类型必须和泛型一致
getInfo<number>(18); // 正确

泛型类

class getMin<T>{
    
     // 定义泛型类
    public arr: T[] = [] // 而后的数据类型都和 T 一致

    push(value: T): void {
    
    
        this.arr.push(value)
    }

    min(): T {
    
    
        let num = this.arr[0]
        this.arr.forEach(item => {
    
    
            if (item < num) {
    
    
                num = item
            }
        })
        return num
    }
}

let g = new getMin<number>() // 实例化类,并指定T代表的数据类型为 number
g.push(78)
g.push(9)
g.push(3)
g.push(4)
console.log(g.min()); // 3

let s = new getMin<string>()  // 实例化类,并指定T代表的数据类型为 string
s.push('s')
s.push('c')
s.push('h')
s.push('e')
console.log(s.min()); // c

泛型接口

第一种方式:
interface getInfoFn {
    
     <T>(value: T, value2: T): T }

let getInfo: getInfoFn = function<T> (name: T, age: T): any {
    
    
    return `我叫${
      
      name},今年${
      
      age}`
}

console.log(getInfo<string>('张三', '18')); // 我叫张三,今年 18 岁

第二种方式:
interface getInfoFn<T> {
    
     (value: T, value2: T): T }

function getInfo<T> (name: T, age: T): any {
    
    
    return `我叫${
      
      name},今年${
      
      age}`
}

let myGetInfo : getInfoFn<string> = getInfo
console.log(myGetInfo('张三', '18')); // 我叫张三,今年 18 岁

工作用一般使用泛型格式:只关注于我需要的数据,不关心数据的具体格式,接口是什么格式数据就是什么格式,别人可以任意定义接口,传入自己需要的数据格式
在这里插入图片描述

持续更新中…

猜你喜欢

转载自blog.csdn.net/xiaoguoyangguang/article/details/119972834