深入浅出 TypeScript

42 阅读5分钟

为什么学TS

image.png

TypeScriptJavaScript
强类型,支持静态和动态类型一种脚本语言,用于创建动态网页
JavaScript 的超集,用于解决大型项目的代码复杂性动态弱类型语言
可以在编译期间发现并纠正错误只能在运行时发现错误
不允许改变变量的数据类型变量可以被赋值成不同类型

image.png

TS基础

基础类型

  1. boolean、number、string
  2. undefined、null
  3. any、unknown、void
  4. never
  5. 数组类型
  6. 元组类型 tuple
function test(x: string l number): boolean {
    if (typeof x === 'string') {
        return true;
    } else if (typeof x === 'number') {
        return false;
    }
    return throwError('参数格式不对');
}
function throwError(message:string): never{
    throw new Error(message);
}

函数类型

  • 定义:TS定义函数类型时要定义输入参数类型和输出类型
  • 输入参数:参数支持可选参数和默认参数
  • 输出参数:输出可以自动推断,没有返回值时,默认为void类型
  • 函数重载:名称相同但参数不同,可以通过重载支持多种类型
function add(x: number[]): number
function add(x: string[]): string
function add(x: any[]): any {
    if (typeof x[e] === 'string') {
        return x.join()
    }
    if (typeof x[0] === 'number') {
        return x.reduce((acc,cur)=>acc + cur)
    }
}

interface

  1. 定义:接口是为了定义对象类型
  2. 特点:
  • 可选属性: ?
  • 只读属性: readonly
  • 可以描述函数类型
  • 可以描述自定义属性
  1. 总结:接口非常灵活 duck typing
interface RandomKey {
    [propName: string]: string
}
const obj: RandomKey = {
    a: 'hello',
    b:'world',
    c:'typescript'
}

定义:写法和JS差不多,增加了一些定义
特点:

  • 增加了 public、private、protected 修饰符 -抽象类:
    • 只能被继承,不能被实例化
    • 作为基类,抽象方法必须被子类实现
  • interface约束类,使用implements关键字

进阶

  1. 联合类型 |
let num:string | number
num=8;
num='string';
  1. 交叉类型 &
interface Person{
    name:string,
    age:number
}
type Student=Person & {grade:number}
const stu:Student
stu.grade=20
  1. 类型断言
function getLength(arg :number | string):number{
    const str=arg as string
    if(str.length){
        return str.length
    }else{
        const number=arg as number
        returtn number.toString().length
     }
}
  1. 类型别名(type interface)
  • 定义:给类型起个别名
  • 相同点:
  1. 都可以定义对象或函数
  2. 都允许继承
  • 差异点:
  1. interface是TS用来定义对象,type是用来定义别名方便使用
  2. type可以定义基本类型,interface不行;
  3. interface可以合并重复声明,type不行;

这里我还是对type和interface的区别不是很清楚,所以我去找了篇文章看了下,发现了以下区别点,大家可以看下

相同点

    type exampleType1 = {
        name: string
    }
    interface exampleInterface1 {
        name: string
    }
    
    
    type exampleType2 = exampleType1 & {
        age: number
    }
    type exampleType2 = exampleInterface1 & {
        age: number
    }
    interface exampleInterface2 extends exampleType1 {
        age: number
    }
    interface exampleInterface2 extends exampleInterface1 {
        age: number
    }

可以看到对于interface来说,继承是通过 extends 实现的,而type的话是通过  &  来实现的,也可以叫做 交叉类型

还有一种情况需要注意,示例如下

    type exampleType1 = {
        name: string
    }
    interface exampleInterface1 {
        name: string
    }
    
    // 会报错,对于同一个属性,其类型必须一致
    interface exampleInterface2 extends exampleInterface1 {
        name: number
    }
    interface exampleInterface2 extends exampleType1 {
        name: number
    }
    
    //不会报错,但是number和string进行交叉后,得到的是never,因此name属性的类型会变成never
    type exampleType2 = exampleInterface1 & {
        name: number
    }
    type exampleType2 = exampleType1 & {
        name: number
    }

不同点

  • type可以定义 基本类型的别名,如 type myString = string

  • type可以通过 typeof 操作符来定义,如 type myType = typeof someObj

  • type可以申明 联合类型,如 type unionType = myType1 | myType2

  • type可以申明 元组类型,如 type yuanzu = [myType1, myType2]

以下说说interface可以做到,但是type不可以做到的事情

  1. interface可以 声明合并
    interface test {
        name: string
    }
    interface test {
        age: number
    }
    
    /*
        test实际为 {
            name: string
            age: number
        }
    */

这种情况下,如果是type的话,就会报 重复定义 的警告,因此是无法实现 声明合并 的

还有一种情况需要注意

   /*
      会报错,如果重复定义同一个属性,其类型必须相同
   */
   interface test {
       name: string
   }
   interface test {
       name: number
   }

通过以上,我对type和interface的区别也更加清楚了

泛型

基本定义

  1. 泛型的语法是>里面写类型参数,一般用T表示
  2. 使用时有两种方法指定类型:
    1. 定义要使用的类型
    2. 通过TS类型推断,自动推导类型
  3. 泛型的作用是临时占位,之后通过传来的类型进行推导
function print<T>(arg:T):T {
    console.log(arg)
    return arg
}
print<string>('hello') // 定义T为 string
print('heLlo') // TS 类型推断,自动推导类型为 string

基本操作符

  • typeof:获取类型
interface Person{
    name:string;
    age:number;
}
const sem:Person={name:'nike',age:30}

type Sem= typeof sem;//type Sem =Person
  • keyof: 获取所有键
interface Person{
    name:string;
    age:number;
}
type H1=keyof Person;//"name" | "age"
type H2=keyof Person[];//"length" | "toString" | "pop" | "push" | "concat" | "join"

  • in:遍历枚举类型
type Keys="a" | "b" | "c"
type Obj={
    [p in Keys]:any
} //-> {a:any,b:any,c:any}
  • T[K]: 索引访问
interface IPerson{
    name:string;
    age:number;
}
let type1:IPerson['name']//string
let type2:IPerson['age']//number
  • extends:泛型约束
interface Length{
    length:number
}

function Log<T extends Length>(arg:T):T{
    console.log(arg.length);
    return arg;
}

Log({value:3})//提醒出现错误
Log({length:3})

常用工具类型

  • Partial:将类型属性变为可选

  • Required:将类型属性变为必选

  • Readonly:将类型属性变为只读

  • Pick、Record...

TS实战

声明文件

  • declare:三方库需要类型声明文件

  • .d.ts:声明文件定义

  • @types:三方库TS类型包

  • tsconfig.json:定义TS的配置

总结

现在只是学习到了TS的皮毛部分,不过对其有了大概的理解,简而言之就是对js的弱类型进行限制,达到一个更好的代码规范和开发环境,总之首先要用起来 只有不断地基于实战练习最终才能掌握一门技术的精髓

最后还是推荐给大家几个我认为比较好的文章

type和interface的区别知多少? - 掘金 (juejin.cn)
2022年了,我才开始学 typescript ,晚吗?(7.5k字总结) - 掘金 (juejin.cn)