深入浅出TypeTypeScript学习笔记 | 青训营

深入浅出TypeTypeScript

为什么要学TypeScript?

TS在社区的活跃度越来越高

TypeScript vs JavaScript

TS的优势:

  1. 类型化思维方式,使开发更严谨,提前发现错误,减少改Bug时间

  2. 类型系统提高了代码可读性,维护和重构代码更加容易

  3. 补充了接口、枚举等开发大型应用时JS缺失的功能

TS带来了什么?

  • 类型安全
  • 下一代JS特性
  • 完善的工具链

TS不仅仅是一门语言,更是生产力工具

TS推荐

  • Awesome TypeScript:TS开源教程及应用
  • Byte Tech:TS&React:React + TypeScript开发模式介绍
  • Typescript Playground:TS到JS在线编译

TS基础

基础类型

  • boolean、number、string
  • 枚举enum
  • any、unknown、void
  • never
  • 数组类型[]
  • 元祖类型tupte

函数类型

定义:TS定义函数类型时要定义输入参数类型和输出类型

输入参数:参数支持可选参数和默认参数

输出参数:输出可以自动推断,没有返回值时,默认为void类型

函数重载:名称相同但参数不同,可以通过重载支持多种类型

pickCard方法根据传入参数的不同会返回两种不同的类型。 如果传入的是代表纸牌的对象,函数作用是从中抓一张牌。 如果用户想抓牌,我们告诉他抓到了什么牌。 但是这怎么在类型系统里表示呢。 方法是为同一个函数提供多个函数类型定义来进行函数重载。 编译器会根据这个列表去处理函数的调用。 重载pickCard函数:

typescript 复制代码
let suits = ["hearts", "spades", "clubs", "diamonds"]; 
function pickCard(x: {suit: string; card: number; }[]): number;
function pickCard(x: number): {suit: string; card: number; }; 
function pickCard(x): any { 
// Check to see if we're working with an object/array 
// if so, they gave us the deck and we'll pick the card 
if (typeof x == "object") {
let pickedCard = Math.floor(Math.random() * x.length); 
return pickedCard; 
} 
// Otherwise just let them pick the card 
else if (typeof x == "number") { 
let pickedSuit = Math.floor(x / 13); 
return { suit: suits[pickedSuit], card: x % 13 };
 } 
} 
let myDeck = [{ suit: "diamonds", card: 2 }, { suit: "spades", card: 10 }, { suit: "hearts", card: 4 }]; 
let pickedCard1 = myDeck[pickCard(myDeck)];
alert("card: " + pickedCard1.card + " of " + pickedCard1.suit); 

let pickedCard2 = pickCard(15); 
alert("card: " + pickedCard2.card + " of " + pickedCard2.suit);

为了让编译器能够选择正确的检查类型,它与JavaScript里的处理流程相似。 它查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。

interface

定义:接口是为了定义对象类型

特点:

  • 可选属性:?

接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。带有可选属性的接口与普通的接口定义差不多,只是在可选属性名字定义的后面加一个?符号。

可选属性在应用"option bags"模式时很常用,即给函数传入的参数对象中只有部分属性赋值了。下面是应用了"option bags"的例子:

typescript 复制代码
interface SquareConfig {
    color?: string; 
    width?: number; 
} 
function createSquare(config: SquareConfig): {color: string; area: number} { 
  let newSquare = {color: "white", area: 100}; 
  if (config.color) { 
     newSquare.color = config.color; 
     } 
     if (config.width) { 
       newSquare.area = config.width * config.width; 
       } 
       return newSquare; 
} 
let mySquare = createSquare({color: "black"});
  • 只读属性:readonly

一些对象属性只能在对象刚刚创建的时候修改其值。

typescript 复制代码
interface Point {
   readonly x: number; 
   readonly y: number; 
}
  • 可以描述函数类型
  • 可以描述自定义属性

总结:接口非常灵活duck typing

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

特点: 增加了public、private、protected修饰符 抽象类:

  • 只能被继承,不能被实例化

在TypeScript里,我们可以使用常用的面向对象模式。当然,基于类的程序设计中最基本的模式是允许使用继承来扩展现有的类。

typescript 复制代码
class Animal { 
    name:string; 
    constructor(theName: string) { this.name = theName; }      
    move (distanceInMeters: number = 0) { 
         console.log(`${this.name} moved ${distanceInMeters}m.`); 
         } 
} 
class Snake extends Animal { 
    constructor(name: string) { super(name); } 
    move(distanceInMeters = 5) { 
        console.log("Slithering..."); 
        super.move(distanceInMeters); 
     } 
} 
class Horse extends Animal { 
    constructor(name: string) { super(name); } 
    move(distanceInMeters = 45) { 
        console.log("Galloping..."); 
        super.move(distanceInMeters); 
    } 
} 

let sam = new Snake("Sammy the Python"); 
let tom: Animal = new Horse("Tommy the Palomino"); 

sam.move(); 
tom.move(34);
  • 作为基类,抽象方法必须被子类实现
  • interface约束类,使用implements关键字

TS进阶

高级类型

  • 联合类型 |
  • 交叉类型 &
  • 类型断言
  • 类型别名(type VS interface) 定义:给类型起个别名

相同点:

  • 都可以定义对象或函数
  • 都允许继承

差异点:

  • interface是TS用来定义对象,type是用来定义别名方便使用;
  • type可以定义基本类型,interface不行
  • interface可以合并重复声明,type不行

泛型-什么时候需要泛型

官方定义: 软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

应用场景: 定义一个print函数,这个函数功能是把传入的参数打印出来,再返回这个参数,传入参数的类型是string,函数返回类型为string

基本使用

基本定义: 泛型的语法是<>里面写类型参数,一般用T表示; 例子:identity函数。 这个函数会返回任何传入它的值。 你可以把这个函数当成是echo命令。

不用泛型的话,这个函数可能是下面这样:

typescript 复制代码
function identity(arg: number): number {
    return arg;
}

因此,我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。

typescript 复制代码
function identity<T>(arg: T): T {
    return arg;
}

使用时有两种方法指定类型:

  • 定义要使用的类型
  • 通过TS类型推断,自动推导类型
  • 泛型的作用是临时占位,之后通过传来的类型进行推导

基础操作符

  • typeof:获取类型
  • keyof:获取所有键
  • in:遍历枚举类型
  • T[K]:索引访问
  • extends:泛型约束

常用工作类型

  • Partial:将类型属性变为可选
  • Required:将类型属性变为必选
  • Readonly:将类型属性变为只读
  • Pick、Record......

TypeScript实战

声明文件

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

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

  • @types:三方库TS类型包

  • tsconfig.json:定义TS的配置

    如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项。

    tsconfig.json示例文件:

  • 使用"files"属性

typescript 复制代码
    {
    "compilerOptions": {
        "module": "commonjs",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "outFile": "../../built/local/tsc.js",
        "sourceMap": true
    },
    "files": [
        "core.ts",
        "sys.ts",
        "types.ts",
        "scanner.ts",
        "parser.ts",
        "utilities.ts",
        "binder.ts",
        "checker.ts",
        "emitter.ts",
        "program.ts",
        "commandLineParser.ts",
        "tsc.ts",
        "diagnosticInformationMap.generated.ts"
    ]
}

泛型约束后端口类型

泛型约束后端口类型可以是任何类型,只要满足特定的约束条件。在泛型中,可以使用接口、类或其他泛型类型作为约束条件。

例如,假设有一个泛型函数,用于判断两个对象是否相等:
typescript 复制代码
Copyfunction isEqual<T>(a: T, b: T): boolean {
  return a === b;
}

如果要对泛型进行约束,可以使用接口来定义约束条件。例如,可以定义一个接口 Comparable,表示具有比较相等性的类型:

typescript 复制代码
Copyinterface Comparable {
  equals(other: any): boolean;
}

function isEqual<T extends Comparable>(a: T, b: T): boolean {
  return a.equals(b);
}

在这个例子中,isEqual 函数的泛型参数 T 被约束为实现了 Comparable 接口的类型。这样,只有实现了 equals 方法的类型才能被传递给 isEqual 函数。

相关推荐
Find1 个月前
MaxKB 集成langchain + Vue + PostgreSQL 的 本地大模型+本地知识库 构建私有大模型 | MarsCode AI刷题
青训营笔记
理tan王子1 个月前
伴学笔记 AI刷题 14.数组元素之和最小化 | 豆包MarsCode AI刷题
青训营笔记
理tan王子1 个月前
伴学笔记 AI刷题 25.DNA序列编辑距离 | 豆包MarsCode AI刷题
青训营笔记
理tan王子1 个月前
伴学笔记 AI刷题 9.超市里的货物架调整 | 豆包MarsCode AI刷题
青训营笔记
夭要7夜宵1 个月前
分而治之,主题分片Partition | 豆包MarsCode AI刷题
青训营笔记
三六1 个月前
刷题漫漫路(二)| 豆包MarsCode AI刷题
青训营笔记
tabzzz1 个月前
突破Zustand的局限性:与React ContentAPI搭配使用
前端·青训营笔记
Serendipity5651 个月前
Go 语言入门指南——单元测试 | 豆包MarsCode AI刷题;
青训营笔记
wml1 个月前
前端实践-使用React实现简单代办事项列表 | 豆包MarsCode AI刷题
青训营笔记
用户44710308932421 个月前
详解前端框架中的设计模式 | 豆包MarsCode AI刷题
青训营笔记