news 2026/10/10 2:53:42

【前端】TypeScript学习中…(着重与JS区别)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【前端】TypeScript学习中…(着重与JS区别)

TS是JS+静态类型系统,完全兼容JS,TS通过类型注解、接口、泛型等特性在编写时就能检测类型错误,提前规避bug(JS变量类型动态,可随时变更,运行时才能发现报错)

1、类型

1)基础:number、string、boolean

2)null、undefined

3)any、unknown:可以是所有类型,unknown只能赋值给unknown或者any

any放弃类型校验、unknown相对安全,不能进行运算、调用属性、当作函数等任何操作,使用时类型要具体化,缩小使用范围

function any (info: any): any { return info; }

4)void:函数无返回值用 / void 类型的变量只能赋值为 undefined 和 null

function void(): void { console.log('void'); }

5)array:数组

6)tuple:元组(允许表示一个已知元素数量和类型的数组,各元素的类型不必相同

eg:let tuple:[string, number, boolean] = ['str', 3, true];

越界元素:访问超出元祖长度的元素时,其类型会被限制为元祖中每个类型的联合类型

7)enum:枚举(取值被限定在一定范围内

enum Direction { Up = 1, Down, Left, Right } //数字枚举会自动增长,如果第一个不初始化赋值会从0开始。枚举可以通过名字和下标访问,枚举值和枚举名字互相映射。 console.log(Direction.Up);//0 console.log(Direction[0]);//Up const a = Direction.Up; declare let a: Direction // a声明为Direction,相当于声明联合类型,即a是Direction.Up | Direction.Down | Direction.Left | Direction.Right

8)object:除number,string,boolean,symbol,null或undefined之外的类型

9)never:永不存在的值的类型(出现never其实就是报错,一般不会出现)

function error(message: string): never { throw new Error(message); }

10)symbol:通过Symbol构造函数创建,不可改变且唯一

eg:let sym2 = Symbol("key"); let sym3 = Symbol("key"); sym2 === sym3; // false

TS原始类型包括:boolean、number、string、void、undefined、null、symbol、bigint

注解:

1)函数没有返回值时,返回类型就是void。只有null和undefined可以赋给void。

2)默认情况下null和undefined是所有类型的子类型。开启--strictNullChecks后,null和undefined只能赋值给any和它们各自以及void。

3)number和bigint类型的值不能互相赋值。

4)number是类型,而Number是构造函数

2、类型处理

(1)类型注解:eg:let username: string = "zhangsan"; // 字符串类型

type MyString = string; let str: MyString = "hello";

数组类型写法:

// 写法1:类型[] let numArr: number[] = [1, 2, 3]; numArr.push("4"); // 报错:类型不匹配 // 写法2:Array<类型>(泛型语法) let strArr: Array<string> = ["a", "b", "c"]; // 联合类型数组(允许多种类型) let mixedArr: (number | string)[] = [1, "a", 2];

(2)类型声明了以后,变量用类型:

// 类型声明 interface User { name: string; id: number; // 必选属性 readonly role: string; // 只读属性(初始化后不可修改) age?: number; //?表示可选 [propName: string]: any; //添加未定义的属性,并可以指定属性值的类型 } // 变量定义 const user: User = { name: "zhangsan", id: 1, //如果缺少必选属性就会报错 role: "admin" //只读属性,在这里初始化后不可再修改 // 如果这里放一个User没有声明的属性就会报错 };

(3)面向对象的写法:

interface User { name: string; id: number; } class UserAccount { name: string; id: number; constructor(name: string, id: number) { this.name = name; this.id = id; } } const user: User = new UserAccount("zhangsan", 1);

(4)泛型:声明的泛型类型固定了,传其他类型的值就会报错

interface Backpack<Type> { add: (obj: Type) => void; get: () => Type; } // 这一行简写,告诉 TypeScript 有一个常量,叫做`backpack` declare const backpack: Backpack<string>; // 对象是一个字符串,因为我们在上面声明了它作为 Backpack 的变量部分。 const object = backpack.get(); // 因为 backpack 变量是一个字符串,不能将数字传递给 add 函数。 backpack.add(23);

也可使其自动推导:

// 泛型函数:用<T>表示类型占位符,使用时指定具体类型 function identity<T>(value: T): T { return value; // 输入类型与返回类型一致 } // 使用时指定类型(或让TS自动推导) const str = identity<string>("hello"); // 类型为string const num = identity(123); // 自动推导为number类型

泛型类:

class Stack<T> { private arr: T[] = [] public push(item: T) { this.arr.push(item) } public pop() { this.arr.pop() } } // 泛型约束(约束为接收number和string类型 type Params = number | string; class Stack<T extends Params> { …… }

(5)结构类型:结构匹配只需要匹配对象字段的子集

interface Point { x: number; y: number; } function logPoint(p: Point) { console.log(`${p.x}, ${p.y}`); } const point = { x: 12, y: 26, z: 89 }; logPoint(point); // 打印 "12, 26"

(6)接口继承

// 接口 interface User { id: number; name: string; } // 继承User,新增属性 interface AdminUser extends User { role: "admin"; permissions: string[]; } // 定义AdminUser接口的对象 const admin: AdminUser = { id: 2, name: "wangwu", role: "admin", permissions: ["create", "delete"] };

(7)联合类型

type Status = "pending" | "success" | "failed"; let taskStatus: Status = "pending";

(8)交叉类型(注:交叉类型如果是基本数据类型,合并的时候同名会出现never

type Name = { name: string }; type Age = { age: number }; type Person = Name & Age; // 同时包含name和age属性 const person: Person = { name: "zhangsan", age: 18 };

(9)函数类型

// 写法一: type AddFunc = (a: number, b: number) => number; const add: AddFunc = (x, y) => x + y; // 写法二: function add(a: number, b:number): number { return a + b; }

(10)索引类型

function getValue<T extends object, U extends keyof T>(obj: T, key: U) { return obj[key]; }

3、类型守卫(其实这和JS一致

typeof、in、instanceof、字面量、自定义类型保护,使用is关键字

示例:

if (typeof name === 'string') {} if ('name' in Person) {} if (arg instanceof Person) {} if (arg.name === 'chuck') {}

4、interface、type区别

使用 interface 定义接口, 接口名称一般首字母大写,定义接口的时候,只定义声明即可,不包含具体内容

实现接口的时候,要实现里面的内容,定义的变量比接口少了或多了属性都是不允许的

5、内置类型、infer

  • Readonly:只读

  • Required:全部变成必填

  • Partial:让所有属性都变成可选

  • NonNullable:去除null和undefined

  • Pick:在对象中挑选

  • infer:在 extends 条件语句中待推断的类型变量

type Readonly<T> = { readonly [P in keyof T]: T[P]; }; // T所有属性只读 type Required<T> = { [P in keyof T]-?: T[P] }; // T所有属性必选 type Partial<T> = { [K in keyof T]?: T[K] }; // T所有属性可选 type Diff<T, U> = T extends U ? never : T; // 找出T类型中U不包含的部分 type NonNullable<T> = Diff<T, null | undefined>; // 剔除null和undefined //将T类型中的K键列表提取出来,生成新的子键值对类型 type Pick<T, K extends keyof T> = { [P in K]: T[P] } // 如果T能赋值给(param: infer P) => any,则结果是(param: infer P) => any类型中的参数P // 否则返回为 T,infer P表示待推断的函数参数。 type ParamType<T> = T extends (param: infer P) => any ? P : T;

6、.d.ts

npm install --save-dev @types/node

ts会检测根目录下所有.d.ts文件,里面用declare声明的都是全局的。

declare声明的都没有具体的实现,.d.ts只是为了使代码不报错,没有任何实际功能。

eg: 用script引入jq,直接$()会报错,在.d.ts声明:

declare function $(){}

7、常用工具类型

(1)+和-:两个关键字用于映射类型中给属性添加修饰符,比如-?就代表将可选属性变为必选,-readonly代表将只读属性变为非只读。

type Required<T> = { [P in keyof T]-?: T[P] };

(2)Exclude<T, U>: Exclude 的作用是从T中排除出「可分配」给U的元素。

// 如果T不能赋值给U,则返回该值。如果有多个值不能赋值,则TT是联合类型。 type Exclude<T, U> = T extends U ? never : T; type TT = Exclude<1 | 2, 1 | 3>; // 2

(3)Omit<T, K>:Omit的作用是忽略T中的某些属性

// type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; type Foo = Omit<{ name: string, age: number }, 'name'> // { age: number }

(4)Compute:将交叉类型合并

type Compute<A extends any> = A extends Function ? A : { [K in keyof A]: A[K] }; type R1 = Compute<{ x: 'x' } & { y: 'y' }> // {x: "x", y: "y"} type R2 = Compute<{ x: 'x'; y: 'y1' } & { y: 'y' }> // {x: "x", y: never}

(5)Merge:将两个对象的属性合并

// 先忽略掉O2中存在于O1的属性,然后再与O1合并 type Merge<O1 extends object, O2 extends object> = Compute<O1 & Omit<O2, keyof O1>>; type O1 = { name: string; id: string; }; type O2 = { id: number; from: string; }; type R2 = Merge<O1, O2>; // {name: string, id: string, from: string}

(6)Extract<T, U>:提取T中可以赋值给U的属性

type Extract<T, U> = T extends U ? T : never;

(7)Intersection<T, U>:取同时存在T和U的属性

type Intersection<T extends object, U extends object> = Pick< T, Extract<keyof T, keyof U> & Extract<keyof U, keyof T> >; type Props = { name: string; age: number; visible: boolean }; type DefaultProps = { age: number }; type DuplicatedProps = Intersection<Props, DefaultProps>; // { age: number; }

(8)Overwrite<T, U>:用U的属性覆盖T的相同属性

type Overwrite< T extends object, U extends object, // 将「差集」和「交集」进行「交叉」 I = Diff<T, U> & Intersection<U, T> > = Pick<I, keyof I>; // From T, pick a set of properties whose keys are in the union K type Pick<T, K extends keyof T> = { [P in K]: T[P]; };

(9)Mutable<T>:将T的所有属性的readonly移除

type Mutable<T> = { -readonly [P in keyof T]: T[P] } // Make all properties in T readonly type Readonly<T> = { readonly [P in keyof T]: T[P]; };

(10)Record

// Construct a type with a set of properties K of type T type Record<K extends keyof any, T> = { [P in K]: T; }; type K = 'A' | 'B' | 'C'; // {A: {id: number}, B: {id: number}, C: {id: number}} type result = Record<K, { id: number }>

8、类与面向对象相关概念

  • 类(Class):定义了一件事物的抽象特点,包含它的属性和方法
  • 对象(Object):类的实例,通过 new 生成
  • 面向对象(OOP)的三大特性:封装、继承、多态
  • 封装(Encapsulation):将对数据的操作细节隐藏起来,只暴露对外的接口。外界调用端不需要(也不可能)知道细节,就能通过对外提供的接口来访问该对象,同时也保证了外界无法任意更改对象内部的数据
  • 继承(Inheritance):子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
  • 多态(Polymorphism):由继承而产生了相关的不同的类,对同一个方法可以有不同的响应。比如 Cat 和 Dog 都继承自 Animal,但是分别实现了自己的 eat 方法。此时针对某一个实例,我们无需了解它是 Cat 还是 Dog,就可以直接调用 eat 方法,程序会自动判断出来应该如何执行 eat
  • 存取器(getter & setter):用以改变属性的读取和赋值行为
  • 修饰符(Modifiers):修饰符是一些关键字,用于限定成员或类型的性质。比如 public 表示公有属性或方法

public 公有属性或方法,可在任何地方被访问,默认所有属性和方法都是 public的

private 私有属性或方法,不能在声明它的类的外部访问,也不可以在子类中访问

protected 受保护的属性或方法,和 private 类似,区别是它可以在子类中访问

  • 抽象类(Abstract Class):抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
  • 接口(Interfaces):不同类之间公有的属性或方法,可以抽象成一个接口。接口可以被类实现(implements)。一个类只能继承自另一个类,但是可以实现多个接口

示例:

// 1、接口 interface Person { getName(): string; } // 2、类 class Student implements Person { // 4、implements类实现接口 // 5、修饰符 private id: number; // 私有属性,仅类内部可访问 public name: string; // 公共属性,默认可省略 public constructor(id: number, name: string) { this.id = id; this.name = name; } getName(): string { return this.name; } private getStudentId(): number { return this.id; // 私有方法,仅类内部可调用 } } // 3、对象 const student = new Student(101, "Charlie"); console.log(student.getName()); // 正确 console.log(student.id); // 错误:属性“id”为私有属性,只能在类“Student”中访问 // 6、继承 interface User extends Person, Person2 { // 可以继承多个接口 broadcast: () => void }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 2:53:42

2026跨境电商大洗牌:这3个冷门市场正在闷声发财,现在入局还不晚

过去一年&#xff0c;跨境电商最显著的变化不是某条新规&#xff0c;而是流量与利润的再分配。主流平台广告竞价持续走高&#xff0c;部分品类退货率居高不下&#xff0c;让不少卖家开始把目光移向更细分的区域市场。真正值得留意的机会&#xff0c;往往不在聚光灯下&#xff0…

作者头像 李华
网站建设 2026/10/10 2:53:20

PLC编程必学!S7-1200 FC函数建立与参数详解,一篇讲透

很多刚学西门子S7-1200 PLC编程的新手&#xff0c;都会遇到这样的问题&#xff1a;控制3台电机就要写3遍起保停程序&#xff0c;控制8个指示灯闪烁就要写8段重复代码&#xff0c;程序又长又乱&#xff0c;后期改一个参数&#xff0c;就要把所有重复的程序全改一遍&#xff0c;费…

作者头像 李华
网站建设 2026/10/10 2:51:17

Hadoop实战:用MapReduce和朴素贝叶斯构建用户性别预测模型

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华