一、核心概念与基础

1. 是什么

  • TypeScript(TS)是 JavaScript 的超集,在 JS 基础上添加类型支持,是微软开发的开源编程语言,可在任何运行 JavaScript 的地方运行,如let age1: number = 18(TS 代码)和let age2 = 18(JS 代码)对比,TS 有明确类型标注。

2. 添加类型支持的原因

  • JS 类型系统存在缺陷,多数错误为类型错误,影响开发效率。TS 属于静态类型编程语言,在编译期做类型检查;JS 属于动态类型编程语言,执行期做类型检查。TS 能在编译时(执行前)发现错误,配合开发工具可在编写代码时发现错误,减少找 Bug 和改 Bug 时间。

3. 优势

  • 更早发现错误,提升开发效率;提供代码提示,增强开发体验;提升代码可维护性,便于重构;支持最新 ECMAScript 语法;有类型推断机制,降低使用成本。在多个前端框架中广泛应用,是大中型前端项目首选编程语言。

4. 初体验

  • 环境搭建:Node.js 和浏览器只识别 JS 代码,需安装typescript包(npm i -g typescript)将 TS 转化为 JS,通过tsc -v验证安装,tsc命令实现转化。
  • 运行 TS 代码
    • 传统方式:创建.ts文件,用tsc命令编译生成.js文件,再用node命令执行。
    • 简化方式:安装ts-node包(npm i -g ts-node),用ts-node命令直接运行 TS 文件,内部自动完成转化。

二、常用类型系统

1. 类型注解与类型推论

  • 类型注解:为变量、函数参数、返回值、对象属性和方法等添加类型约束,如let age: number = 18: number为类型注解,约定变量类型,赋值不符会报错。
  • //Typescript代码中有明确的类型,即:number(数值类型)
    let age:number=23;
    
    //JavaScript代码,无明确的类型
    let age2=23;
  • 类型推论:在声明变量并初始化或决定函数返回值时,TS 自动推断类型,可省略类型注解,如let age = 18(TS 推断agenumber类型)。推荐省略能省略的类型注解,利用 VSCode 提示查看类型。

2. 常用基础类型

  • 原始类型:包括numberstringbooleannullundefinedsymbol,书写与 JS 中类型名称一致,如Let age: number = 18
  • 数组类型:推荐number[]写法,也可用Array<string>。元素包含多种类型时,用联合类型表示,如Let arr: (number | string)[] = [1, 'a', 3, 'b'],注意与 JS 中或(||)的区别。
  • //创建数组的方式
    const arr1:string[]=[]
    const arr:number[]=[1,2,3] 
    const arr2:Array<string> = ['basketball','football']
    
    //数组的使用                                                                
    const arr:number[]=[1,2,3,4,5]//创建一个number类型的数组
    const arr1:String[]=["wcr","zs","fcc"]//创建一个string类型的数组
    console.log(arr1.length);//得到长度3
    console.log(arr1[0]);//取值,得到wcr
    //遍历数组arr,从0号索引开始,最大的长度是length-1
    for(let i:number=0;i<arr.length-1;i++){
        console.log(arr[i]);
    }
  • 类型别名(自定义类型):使用type关键字为复杂类型创建别名简化使用,如type CustomArray = (number | string)[],之后可直接用别名作为变量类型注解。可以提高开发效率,避免多次写重复的代码。
  • //类型别名 type 
    type  numtype= number|string|null|Array<String|number>
    //联合类型
    const num:numtype=123
    const A:numtype='123'
    const B:numtype=null
    const C:numtype=[1,2,3]

3. 函数类型

  • 参数与返回值类型指定
    • 单独指定:
    • 同时指定(函数表达式):
  • 特殊情况
    • 无返回值时函数返回值类型为void
    • function greet(name:string):void{
          console.log('hello',name);
      }
    • 可选参数:参数可传可不传时,在参数名后加?,且必须在参数列表末尾

4. 对象类型

是用来描述对象结构的

  • 解释:
    1. 直接使用 {} 来描述对象结构。属性采用属性名: 类型的形式;方法采用方法名(): 返回值类型的形式。
    2. 如果方法有参数,就在方法名后面的小括号中指定参数类型(比如:greet(name: string): void)。
    3. 在一行代码中指定对象的多个属性类型时,使用 ;(分号)来分隔。
    l 如果一行代码只指定一个属性类型(通过换行来分隔多个属性类型),可以去掉 ;(分号)。
    l 方法的类型也可以使用箭头函数形式(比如:{ sayHi: () => void })。

5. 接口:

一般使用interface表示接口,是用来达到复用的目的。

interface Iperson{
    name:string;
    age:number;
    sayHi():void;
}

let person:Iperson={
    name:'jack',
    age:12,
    sayHi(){
        console.log('hi');
    }
}
//解释:
//1. 使用 interface 关键字来声明接口。
//2. 接口名称(比如,此处的 IPerson),可以是任意合法的变量名称。
//3. 声明接口后,直接使用接口名称作为变量的类型。
//4. 因为每一行只有一个属性类型,因此,属性类型后没有 ;(分号)。

//接口和类型别名的区别:二者都是给对象指定类型的;但是接口是给对象指定类型的,类型别名可以为任一类型指定别名。

同时,接口也具有继承的特性,使用extends关键字。

6. 元组

用于确切知道数组元素个数和特定索引对应类型的场景

7. 类型断言

当 TS 推断类型不能满足需求时,使用类型断言指定更具体类型

//定义一个cat的接口
interface cat{
    name:string,
    age:number,
    run:()=>void
}

//定义一个dog的接口
interface dog{
    name:string,
    eat:()=>void
}

//将一个父类断言为子类,首先animals
//可以是cat或者dog类型。
function animal(animals:cat|dog){
//将animals断言为cat类型,那它具有cat
//的属性和方法。
    console.log((animals as cat).age);
    
}
//此时name为dog的类型就具有cat的age属性,为2
console.log({name:"dog",age:2});

8. 字面量类型

let str='Hello TS'

function changeDirection(direction: 'left' | 'right'|'top'|'bottom') {
   console.log(direction);
}

总结:特定的字符串、数字等字面量可作为类型,如str类型为'Hello TS'。常与联合类型配合使用,表示一组明确的可选值列表,如函数参数direction只能取'left' |'right'|'top'|'bottom'中的值,相比string类型更精确严谨。

9. 枚举

enum Direction1{//默认值从0开始,递增
    up=8,
    down,
    left,
    right
}

enum Direction2{
    //字符串枚举,枚举成员的值是字符串,
    // 注意: 字符串枚举没有自增长行为,因此,字符串枚举的每个成员必须有初始值。
    up='UP',
    down='down',
    left='left',
    right='right'
}
const a:Direction1=Direction1.up
console.log(a);//8

const c:Direction2=Direction2.up
console.log(c);/UP

总结:
1. 使用enum关键字定义枚举
2. 约定枚举名称、枚举中的值以大写字母开头
3. 枚举中的多个值之间通过 ,(逗号)分隔
4. 定义好枚举后,形参直接使用枚举名称作为类型注解
5. 实参的值可以是枚举 Direction 成员的任意一个,接通过点(.)语法访问枚举的成员
6. 从输出结果为0,我们可以知道表示枚举的值是会携带默认值的,从 0 开始自增的数值
7. 通过扩展1能知道数字的起始值可以自定义,并且自增只针对数字类型
8. 枚举中的成员也可以自定义初始化值 

10. any 类型

原则上不推荐使用,会使 TS 失去类型保护优势。

解释:以上操作无类型错误提示,但可能存在错误。其他隐式具有any类型的情况有声明变量不提供类型也不提供默认值、函数参数不加类型,应尽量避免使用,除非临时用于 “避免” 书写复杂类型。

11. typeof

在 TS 中,typeof可在类型上下文中引用变量或属性的类型(类型查询),用于根据已有变量的值获取其类型简化类型书写。

解释:
1. 使用 typeof 操作符来获取变量 p 的类型,结果与第一种(对象字面量形式的类型)相同。
2. typeof 出现在类型注解的位置(参数名称的冒号后面)所处的环境就在类型上下文(区别于 JS 代码)。
3. 注意:typeof 只能用来查询变量或属性的类型,无法查询其他形式的类型(比如,函数调用的类型)。

三、高级类型特性

1. class 

  • TS 全面支持class关键字,为其添加类型注解和其他语法(如可见性修饰符等)。
    • 实例属性初始化:
      • class Person{
            age:number;
            gender='男'
            //gender:string='男'
        }
        //解释:
        //1. 声明成员 age,类型为 number(没有初始值)。
        //2. 声明成员 gender,并设置初始值,此时,可省略类型注解(TS 类型推论 为 string 类型)。
      • 构造函数:成员初始化后才能在构造函数中通过this访问,构造函数需指定类型注解,无返回值类型。
        class Person{
            age:number
            gender:string
        
            constructor(age:number,gender:string){
                this.age=age
                this.gender=gender
            }
        }
        
      • 实例方法:方法类型注解与函数用法相同
      • 类继承:有extends(继承父类)和implements(实现接口)两种方式。
        • extends实现继承,子类继承父类后拥有父类和子类所有属性和方法,
          • implements使类必须实现接口中指定的方法和属性。
      • 类成员可见性:包括public(公有的,默认可见性)、protected(受保护的,仅对声明所在类和子类中(非实例对象)可见)、private(私有的,只在当前类中可见)和readonly(只读修饰符,防止在构造函数之外对属性赋值,只能修饰属性不能修饰方法)。

2. 泛型

  • 可在保证类型安全前提下让函数等与多种类型一起工作实现复用,常用于函数、接口、class中。
    • 创建泛型函数:语法为在函数名后加<>尖括号,尖括号内为类型变量(可自定义名称),类型变量作为函数参数和返回值类型,表示参数和返回值具有相同类型,如function id<Type>(value: Type): Type { return value; }
    • 调用泛型函数:可在函数名后<>指定具体类型,也可省略(TS 会根据传入实参自动推断类型变量类型),如const num = id<number>(10); const str = id('a'); let num = id(10);,推荐省略简化调用,但编译器无法推断或推断不准确时需显式传入类型参数。
    • 泛型约束:默认泛型函数类型变量可代表多种类型,可能无法访问属性,需添加约束收缩类型,可指定更具体类型(如Type[])或添加约束(通过extends关键字使用接口约束类型变量,要求传入类型必须具有指定属性),泛型的类型变量可多个且相互约束,如function getProp<Type, Key extends keyof Type>(obj: Type, key: Key) { return obj[key]; }
    • 泛型接口:接口名称后加<类型变量>变为泛型接口,类型变量对接口所有成员可见,使用时需显式指定具体类型,如interface IdFunc<Type> { id: (value: Type) => Type; ids: () => Type; } let obj: IdFunc<number> = { id(value) { return value; }, ids() { return [1, 3, 5]; } },JS 中的数组在 TS 中是泛型接口,TS 会根据数组类型自动设置类型变量。
    • 泛型类:class名称后加<类型变量>变为泛型类,创建实例时需在类名后<>指定明确类型,如class GenericNumber<NumType> { defaultValue: NumType; add: (x: NumType, y: NumType) => NumType; } const myNum = new GenericNumber<number>()。
    • 泛型工具类型:TS 内置基于泛型实现的工具类型,如Partial<Type>(将Type所有属性设为可选)、Readonly<Type>(将Type所有属性设为只读)、Pick<Type, Keys>(从Type中选一组属性构造新类型)、Record<Keys, Type>(构造对象类型,属性键为Keys,属性类型为Type)。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐