小白20分钟学习最简单的typescript

642 阅读6分钟

typescript的入门教程一般都很复杂,但是日常开发中不会用到那么高级的用法,本文简单地讲一下最简单的版本的ts,帮助小白快速入门。先入门把代码写起来,再慢慢提升。

类型

image.png 首先,ts是js+类型,使用:后面声明变量的类型

数组

数组的写法 image.png

元组

里面能放不同类型的元素(区别与数组只能放同一种类型)

image.png

接口

image.png

可选属性

只读属性:

image.png

readonly和const的区别:readonly用在属性上,const用在变量上

函数

可选参数

image.png

函数不仅是输入输出(参数,返回值有类型),函数本身也有类型

image.png

用interface声明函数类型

image.png

对比直接写是箭头

image.png

类型推论

typescript能推断出类型,比如一个函数的传参是number,number ,操作是加。typescript能自动推断出返回值是number,因此可以省略返回值类型的书写

联合类型

image.png

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

image.png

如果需要在不确定具体类型的时候使用其中一种类型的属性或方法,使用类型断言

断言

image.png

告诉编译器自己比编译器更懂类型

type guard :缩小类型范围

在 TypeScript 中,type guard(类型守卫)是一种特殊的表达式,用于在运行时检查变量的类型,同时让 TypeScript 编译器在编译时也能推断出变量的具体类型,从而实现更精确的类型控制。

类型守卫的核心作用是:在特定作用域内缩小变量的类型范围,让 TypeScript 从更宽泛的类型(如联合类型)推断出更具体的类型,避免不必要的类型断言,提高代码的安全性和可读性。

image.png

枚举

image.png

泛型

定义函数,接口和类的时候,不预先指定具体类型,而是在使用的时候再指定类型

image.png

T 相当于是占位符(相当于一个形参,使用时可以把类型传入)

举例:交换元组中两项的顺序

image.png

约束泛型

image.png 在 TypeScript 中,约束泛型(Generic Constraints)  是一种限制泛型类型范围的机制,它可以让泛型只能接收任意类型,而是只能接收满足特定条件的类型。通过约束,我们可以确保泛型参数具有某些特定的属性或方法,从而在代码中安全地使用这些属性或方法。

为什么需要约束泛型?

如果不约束泛型,当我们尝试访问泛型类型的某个属性或方法时,TypeScript 会报错,因为它无法确定该类型是否包含这些成员。例如:

typescript

function getLength<T>(arg: T): number {
  return arg.length; // 错误:类型“T”上不存在属性“length”
}

此时就需要约束泛型,指定 T 必须包含 length 属性。

如何约束泛型?

使用 extends 关键字可以约束泛型,语法如下:

typescript

// 约束 T 必须是包含 length 属性的类型
function getLength<T extends { length: number }>(arg: T): number {
  return arg.length; // 现在合法了
}

这里的 { length: number } 就是对 T 的约束,表示 T 必须是具有 length 属性(且属性值为 number 类型)的类型。

常见的约束场景

  1. 约束为特定接口 / 类型可以约束泛型必须实现某个接口或继承某个类:

    typescript

    interface HasId {
      id: number;
    }
    
    // 约束 T 必须实现 HasId 接口
    function logId<T extends HasId>(item: T): void {
      console.log(item.id); // 安全访问 id 属性
    }
    
    // 合法:User 实现了 HasId
    type User = { id: number; name: string };
    logId<User>({ id: 1, name: "Alice" });
    
    // 错误:缺少 id 属性
    logId({ name: "Bob" });
    

奇怪,extends不是继承吗

在 TypeScript 中,extends 确实有 “继承” 的含义,但在泛型约束场景中,它的含义更接近于 “限制范围” 或 “满足条件”,而非传统面向对象中的 “继承”。

具体来说:

  1. 在类 / 接口中extends 表示 “继承”

    typescript

    class Animal { /* ... */ }
    class Dog extends Animal { /* ... */ } // Dog 继承 Animal
    

    这里 Dog extends Animal 表示 Dog 是 Animal 的子类,继承了父类的属性和方法。

  2. 在泛型约束中extends 表示 “必须满足条件”

    typescript

    function fn<T extends { length: number }>(arg: T) { ... }
    

    这里的 T extends { length: number } 并不表示 “T 继承了这个接口”,而是表示 “T 必须是具有 length 属性的类型”(可以是直接包含该属性的类型,也可以是继承了该属性的类型)。

    例如:

    • string 类型本身有 length 属性,所以可以传入
    • Array 类型本身有 length 属性,所以可以传入
    • 自定义类型 { length: number; name: string } 也符合条件

简单说:

  • 类 / 接口中的 extends 是 “继承关系”(子类 IS-A 父类)
  • 泛型约束中的 extends 是 “条件限制”(类型 MUST-HAVE 某些特征)

这两种场景下,extends 的核心思想和用法是有区别的,但核心思想相通 —— 都是在描述 “一种类型与另一种类型的关联关系”。

总结:约束泛型的关键是在传入值中使用extends,就可以约束传入值的条件,而不是想传入啥就传入啥

泛型在类中的使用

image.png

泛型在接口中的使用

image.png

用来创建特定类型的容器

类型别名

image.png

字面量类型

image.png

在 TypeScript 中,字面量类型(Literal Types)  是一种表示具体值的类型,而不是表示一组值的类型。它限定变量只能取某个特定的值,而不是某个类型的任意值。

常见的字面量类型

  1. 字符串字面量类型限定变量只能是某个具体的字符串:

    type Direction = 'up' | 'down' | 'left' | 'right';
    
    let move: Direction;
    move = 'up';    // 合法
    move = 'down';  // 合法
    move = 'forward'; // 错误:只能是指定的四个值之一
    
  2. 数字字面量类型限定变量只能是某个具体的数字:

    type Score = 0 | 1 | 2 | 3;
    
    let currentScore: Score;
    currentScore = 2;  // 合法
    currentScore = 5;  // 错误:超出指定范围
    
  3. 布尔字面量类型更具体的 boolean 类型,只能是 true 或 false

    type TrueOnly = true;
    type FalseOnly = false;
    
    let isSuccess: TrueOnly = true;  // 合法
    let isError: FalseOnly = false;  // 合法
    isSuccess = false;  // 错误
    
  4. 对象字面量类型限定对象的属性和值必须完全匹配某个字面量结构:

    type User = {
      name: 'Alice';
      age: 30;
    };
    
    const user: User = {
      name: 'Alice',
      age: 30
    };  // 合法
    
    const user2: User = {
      name: 'Bob',  // 错误:name 必须是 'Alice'
      age: 30
    };
    

字面量类型的典型用途

  1. 限制取值范围比如定义枚举式的固定选项(替代部分枚举场景):

    // 定义按钮类型
    type ButtonType = 'primary' | 'secondary' | 'danger';
    
    function renderButton(type: ButtonType) {
      // 根据类型渲染不同样式的按钮
    }
    
    renderButton('primary');  // 合法
    renderButton('warning');  // 错误:不存在的类型
    

    联合类型/交叉类型

    1. 联合类型(Union Types)

联合类型用 | 符号表示,代表 “或” 的关系,即一个变量可以是几种类型中的任意一种

语法
type UnionType = Type1 | Type2 | Type3;
示例
// 字符串或数字类型
type StringOrNumber = string | number;

let value: StringOrNumber;
value = "hello";  // 合法
value = 42;       // 合法
value = true;     // 错误:不是 string 或 number

2. 交叉类型(Intersection Types)

2.交叉类型用 & 符号表示,代表 “且” 的关系,即一个变量需要同时满足所有类型的特征(合并所有类型的属性 / 方法)。

语法
type IntersectionType = Type1 & Type2 & Type3;
示例
// 同时具有 Name 和 Age 的属性
type Name = { name: string };
type Age = { age: number };
type Person = Name & Age;  // { name: string; age: number }

const person: Person = {
  name: "Alice",
  age: 30  // 必须同时包含 name 和 age
};

类型声明

image.png

在d.ts文件里声明类型

image.png 另一种写法