typescript的入门教程一般都很复杂,但是日常开发中不会用到那么高级的用法,本文简单地讲一下最简单的版本的ts,帮助小白快速入门。先入门把代码写起来,再慢慢提升。
类型
首先,ts是js+类型,使用:后面声明变量的类型
数组
数组的写法
元组
里面能放不同类型的元素(区别与数组只能放同一种类型)
接口
可选属性
只读属性:
readonly和const的区别:readonly用在属性上,const用在变量上
函数
可选参数
函数不仅是输入输出(参数,返回值有类型),函数本身也有类型
用interface声明函数类型
对比直接写是箭头
类型推论
typescript能推断出类型,比如一个函数的传参是number,number ,操作是加。typescript能自动推断出返回值是number,因此可以省略返回值类型的书写
联合类型
联合类型只能访问联合类型的所有属性上的共有的属性或共有的方法
如果需要在不确定具体类型的时候使用其中一种类型的属性或方法,使用类型断言
断言
告诉编译器自己比编译器更懂类型
type guard :缩小类型范围
在 TypeScript 中,
type guard(类型守卫)是一种特殊的表达式,用于在运行时检查变量的类型,同时让 TypeScript 编译器在编译时也能推断出变量的具体类型,从而实现更精确的类型控制。类型守卫的核心作用是:在特定作用域内缩小变量的类型范围,让 TypeScript 从更宽泛的类型(如联合类型)推断出更具体的类型,避免不必要的类型断言,提高代码的安全性和可读性。
枚举
泛型
定义函数,接口和类的时候,不预先指定具体类型,而是在使用的时候再指定类型
T 相当于是占位符(相当于一个形参,使用时可以把类型传入)
举例:交换元组中两项的顺序
约束泛型
在 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 类型)的类型。
常见的约束场景
-
约束为特定接口 / 类型可以约束泛型必须实现某个接口或继承某个类:
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确实有 “继承” 的含义,但在泛型约束场景中,它的含义更接近于 “限制范围” 或 “满足条件”,而非传统面向对象中的 “继承”。具体来说:
在类 / 接口中:
extends表示 “继承”typescript
class Animal { /* ... */ } class Dog extends Animal { /* ... */ } // Dog 继承 Animal这里
Dog extends Animal表示Dog是Animal的子类,继承了父类的属性和方法。在泛型约束中:
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,就可以约束传入值的条件,而不是想传入啥就传入啥
泛型在类中的使用
泛型在接口中的使用
用来创建特定类型的容器
类型别名
字面量类型
在 TypeScript 中,字面量类型(Literal Types) 是一种表示具体值的类型,而不是表示一组值的类型。它限定变量只能取某个特定的值,而不是某个类型的任意值。
常见的字面量类型
-
字符串字面量类型限定变量只能是某个具体的字符串:
type Direction = 'up' | 'down' | 'left' | 'right'; let move: Direction; move = 'up'; // 合法 move = 'down'; // 合法 move = 'forward'; // 错误:只能是指定的四个值之一 -
数字字面量类型限定变量只能是某个具体的数字:
type Score = 0 | 1 | 2 | 3; let currentScore: Score; currentScore = 2; // 合法 currentScore = 5; // 错误:超出指定范围 -
布尔字面量类型更具体的
boolean类型,只能是true或false:type TrueOnly = true; type FalseOnly = false; let isSuccess: TrueOnly = true; // 合法 let isError: FalseOnly = false; // 合法 isSuccess = false; // 错误 -
对象字面量类型限定对象的属性和值必须完全匹配某个字面量结构:
type User = { name: 'Alice'; age: 30; }; const user: User = { name: 'Alice', age: 30 }; // 合法 const user2: User = { name: 'Bob', // 错误:name 必须是 'Alice' age: 30 };
字面量类型的典型用途
-
限制取值范围比如定义枚举式的固定选项(替代部分枚举场景):
// 定义按钮类型 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
};
类型声明
在d.ts文件里声明类型
另一种写法