一天速通TypeScript入门基础知识


一天速通TypeScript入门基础知识

原创 已于 2025-07-13 20:29:54 修改 · 粉丝可见 · 996 阅读 · 20 · 22 GEO检测 · 编辑
文章链接:https://blog.csdn.net/hacker_51/article/details/149303107

目录

[TOC]

一、TypeScript简介

  1. TypeScript 由 微软 开发,是基于JavaScript 的一个 扩展语言

  2. TypeScript 包含了JavaScript 的所有内容,即:TypeScript 是JavaScript 的 超集

  3. TypeScript 增加了:静态类型检查、接口、泛型等很多 现代开发特性 ,因此更适合 大型项目 的开发。

  4. TypeScript 需要 编译 为 JavaScript ,然后交给浏览器或其他 JavaScript 运行环境执行。

二、为何需要TypeScript

1、今非昔比的JavaScript(了解)

  • ·JavaScript 当年诞生时的定位是浏览器 脚本语言 ,用于在网页中嵌入一些 简单的逻辑 ,而且代码量很少。

  • 随着时间的推移,JavaScript 变得越来越流行,如今的JavaScript 已经可以 全栈编程 了。

  • 现如今的 JavaScript 应用场景 比当年 丰富 的多。 代码量 也比当年 很多,随便一个JavaScript 项目的代码量,可以轻松的达到几万行,甚至十几万行!

  • 然而 JavaScript 当年 “出生简陋” 没考虑到如今的应用场景和代码量,逐渐的就出现了 很多困扰

2、JavaScript 中的困扰

1、不清不楚的数据类型

1
2
3
let welcome = 'hello';
welcome(); // 此行报错:Uncaught TypeError: welcome is not a function 。
// 有时候接收到的一个函数,但是太多代码,并不记得自己定义了这个变量,编辑器并没有校验,就会导致这个错误。

2、有漏洞的逻辑

1
2
3
4
5
6
7
8
const str = Date.now() % 2  ? '奇数' : '偶数';

if (str !== '奇数') {
alert('这不是奇数');
} else if (str === '偶数') {
// 逻辑漏洞 但是没有校验提示
alert('这不是奇数');
}

3、访问不存在的属性

1
2
const obj = { width: 100, height: 200 };
const area = obj.width * obj.height; // 访问不存在的对象,但是也没有检验提示

4、低级的拼写错误

1
2
3
4
const str = 'hellow,world'
// 拼写错误也没有校验提示
const UpperStr = str.toUperCase() // 此行报错 Uncaught TypeError: str.toUperCase is not a function
console.log(UpperStr);

3、静态类型检查

  • 在代码运行前进行检查,发现代码的错误或不合理之处,减小运行时异常的出现的几率,此种检查叫『 静态类型检查 』,TypeScript 和核心就是『静态类型检查』,简言之就是 把运行时的错误前置

  • 同样的功能,TypeScript 的代码量要 大于 JavaScript,但由于 TypeScript 的代码结构更加清晰,在后期代码的维护中 TypeScript 却 远胜于 JavaScript。

ts 是静态类型检查。无需运行就可以给你校验基本错误。

三、编译TypeScript

浏览器不能直接运行 TypeScript 代码,需要编译为 JavaScript 再交由浏览器解析器执行。

1、命令行编译(了解即可)

第一步 :创建 demo.ts 文件。例如:

1
2
3
4
5
const person = {
name: 'Angindem',
age: 32
};
console.log(`my name is ${person.name} and I'm ${person.age} years old.`);

第二步 :全局安装 TypeScript

1
npm i -g typescript

第三步 :使用命令编译 .ts 文件

1
tsc demo.ts

2、自动化编译

第一步 :创建 TypeScript 编译控制文件

1
tsc --init
  1. 工程中会生成一个 tsconfig.json 配置文件,其中包含着很多编译时的配置

  2. 观察发现,默认编译的 JS 版本是 ES7 ,我们可以手动调整为其他版本。

第二步 :监视目录中的 .ts 文件变化

1
tsc --watch

第三步 :加上指定属性进行小优化,当编译出错时不生产 .js 文件

1
tsc --noEmitOnError --watch

(不推荐命令行加上属性优化)

所有的属性开启应该在 tsconfig.json 中进行开启。然后我们执行第二步就行了。

如果使用了脚手架,如 Vue 或React。我们可以发现我们不用以上编译了。而是基于 webpack 或 vite  进行编译运行。随后我们使用 npm 或 yarn 或 pnpm 执行相对应的 script 常量名即可。

四、类型声明(这里可以算是真正开始TypeScript)

使用 “ ” 来对 变量函数形参 ,进行 类型声明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let a: string;
let b: number;
let c: boolean;

a = 'hello world'
b = -123
c = true
function count(x: number, y: number): number /*函数右括号后边进行函数返回值类型声明*/
{
return x + y
}

// count(1) // 警告:应有 2 个参数,但获得了 1 个
// count(1, 2,3) // 警告:应有 2 个参数,但获得了 3 个
// count(100,'200') // 警告:类型“string”的参数不能赋给类型“number”的参数

// let result = count(1, 2);
// console.log(result);

在 “ ” 后也可以写 常量值类型 ,不过实际开发中用的不多。

1
2
3
4
5
6
7
8
9
10
11
let a: string;

// 声明指定存储的 常量值
let b: 'hello';

a = 'asd'
// b = 'fas'

// 只能存储 hello
b = 'hello'
console.log(b);

五、类型推断

1
2
3
let d = -99; // 等价于  let d: number = -99;

let e = 'hello'; // 等价于 let e: string = 'hello';

六、类型总览

1、JavaScript 中的数据类型

1
2
3
4
5
6
7
8
9
10
string
number
boolean
null
undefined
bigint
symbol
object

备注:其中 object 包含:ArrayDateError 等......

2、TypeScript 中的数据类型

1
2
3
4
5
6
7
8
9
10
11
12
13
1、上述所有 JavaScript 类型

2、六个新类型
any
② unknow
never
void
⑤ tuple
enum

3、两个用户自定义类型的方式
type
interface

注意点:

在 JavaScript 中的这些内置构造函数:Number、它们用于创建对应String 、Boolean,的包装对象,在日常开发时 很少使用 ,在 Typescript 中也是同理,所以在 Typescript 中进行类型声明时,通常都是用小写的 number、string、boolean

1
2
3
4
5
6
7
8
9
10
11
12
13
let str1: string // TS 官方推荐的写法

str1 = 'hello world'

/*
不能将类型"String" 赋给类型 "string"。
“string” 是基元,但 “String” 是包装器对象。如可能,首选使用基元类型。
*/
// str1 = new String('hello world');

let str2: String
str2 = 'hello world'
str2 = new String('hello world')

①、 原始类型 VS 包装对象

  • 原始类型 :如 number、string、boolean ,在JavaScript 中是简单数据类型,它们在内存占用空间少,处理速度快。

  • 包装对象 :如 Number 对象、string对象、Boolean 对象,是复杂类型,在内存中占用更多空间,在日常开发时很少由开发人员自己创建包装对象。

②. 自动装箱 :JavaScript 在必要时会自动将原始类型包装成对象,以便调用方法或访问属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 原始类型字符串
let str= 'hello';
//当访问str.length时,Javascript引擎做了以下工作:
let size = (function () {
// 1.自动装箱:创建一个临时的string对象包装原始字符串
let tempStringObject =new String(str);
//2.访问string对象的length属性
let lengthValue = tempStringObject.length;
// 3.销毁临时对象,返回长度值
//(Javascript引擎自动处理对象销毁,开发者无感知)
return lengthValue,
})();
console.log(size);//输出:

七、常用类型

1、any

any 的含义是:任意类型,一旦将变量类型限制为 any,那就意味着 放弃了 对该变量的类型检查。

1
2
3
4
5
6
7
8
9
10
11
12
let a: any;  // 显示类型指定
a = 1;
a = "1";
a = true;
a = [1, 2, 3];


let b; // 隐式类型转换
b = 1;
b = "1";
b = true;
b = [1, 2, 3];

注意点 :any 类型的变量,可以赋值给任意类型的变量。

2、unknow

unknown 的含义是: 未知类型。

1
2
3
4
5
6
7
8
9
10
//设置a的类型为unknown
let a: unknown
//以下对a的赋值,均正常
a = 100
a = false
a='你好'
//设置x的数据类型为 string

let x: string
x = a //警告:不能将类型“unknown”分配给类型“string

unknown 可以理解为一个类型安全的any,适用于:不确定数据的具体类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//设置a的类型为unknown
let a: unknown
//以下对a的赋值,均正常
a = 100
a = false
a='你好'
//设置x的数据类型为 string

let x: string
// x = a//警告:不能将类型“unknown”分配给类型“string

// 第一种
if (typeof a === 'string') {
x = a
}

// 第二种( as 断言: 断定 a 是 string类型 【有点类似 强制类型转换 】)
x = a as string

// 第三种( <类型> 断言: 断定 a 是 string类型 【有点类似 强制类型转换 】)
x = <string>a

读取 any 类型数据的任何属性都不会报错,而 unknown 正好与之相反。

1
2
3
4
5
6
7
8
9
10
11
12
let str1: string
str1 = "hello world"
str1.toUpperCase() // 无警告


let str2: any
str2 = "hello world"
str2.toUpperCase() // 无警告

let str3: unknown
str3 = "hello world"
str3.toUpperCase() // 警告:“str3”的类型为 " 未知 "

3、never

never 的含义是:任何值都不是,简言之就是不能有值,undefined、null、0 都不行!

①、几乎不用never去直接限制变量,因为没有意义,例如:

1
2
3
4
5
6
let a: never;
// 以下都会警告
// a = 9
// a = '9'
// a = true
// a = [1, 2, 3]

② never 一般是 TypeScript 主动推断出来的

3、never 也可以用户限制函数的返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
function demo(): number{
return 100;
}
// 只有 两种情况 never 才不会爆红:1. 函数死循环 、2. 函数抛出异常
// 死循环
function demo2(): never{
demo2();
}

// 抛出错误
function demo3(): never{
throw new Error('error')
}

4、void

① void 通常用于函数返回值声明,含义:【函数不返回任何值, 调用者也不应依赖其返回值进行任何操作

1
2
3
4
5
6
function logMessage(msg: string): void{
console.log(msg);
// return undefined; // void 能接受的是 undefined
}

logMessage("Hello World!");

注意: 编码者没有编写 return 去指定函数的返回值,所以 1ogMessage 函数是没有 显式返回值 的,但会有一个 隐式返回值 ,就是 undefined ;即:虽然函数返回类型为 void ,但也是可以接受 undefined 的,简单记: undefined 是void 可以接受的一种“空”。

② 以下写法均符合规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 无警告
function logMessage1(msg: string): void{
console.log(msg);
}
// 无警告
function logMessage2(msg: string): void{
console.log(msg);
return;
}
// 无警告
function logMessage3(msg: string): void{
console.log(msg);
return undefined;
}
1
2
3
4
5
6
7
8
9
10
11
12
// function demo1(): void{
// console.log("hello world");
// }
// let result = demo1();
// if (result) { // 警告: void 不应该有操作
// }
function demo2(): undefined{
console.log("hello world");
}
let res = demo2();
if (res) { // undefined :JavaScript 允许 undefined 赋值给任何变量
}

理解 void 与 undefined

  • void 是一个广泛的概念,用来表达“空”,而 undefined 则是这种“空”的具体实现之一。

  • 因此可以说 undefined 是 void 能接受的“空”状态的一种具体形式。

  • 换句话说:void 包含 undefined ,但 void 表达的语义超越了单纯的 undefined ,它是一种意图上的约定,而不仅仅是特定值的限制。

总结 :若函数返回类型为 void ,那么:

  1. 从语法上讲:函数是可以返回 undefined 的,至于显示返回,还是隐式返回,这无所谓!

  2. 从语义上讲:函数调用者不应关心函数返回的值,也不应依赖返回值进行任何操作!即使返回了 undefined 值。

5、object

关于objectObject, 直接说结论:实际开发中用的相对较少,因为范围太大了。

object(小写)

object (小写)的含义是:所有非原始类型,可存储:对象、函数、数组等,由于限制的范围比较宽泛,在实际开发中使用的相对较少

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let a: object   // a 能存储的类型是 【非原始类型】

a = {}
a = { name: 'why' }
a = [1, 3, 5, 7, 9]
a = function () { }
a = new String('why')

class Person { }
a = new Person()

// 以下代码,是将 【原始类型】 赋给a,有警告
a = 1 // 警告: 不能将类型“number”分配给类型“object”。
a = true // 警告:不能将类型“boolean”分配给类型“object”。
a = 'why' // 警告:不能将类型“string”分配给类型“object”。
a = null // 警告:不能将类型“null”分配给类型“object”。
a = undefined // 警告:不能将类型“undefined”分配给类型“object”。

Object (大写)

官方描述 :所有可以调用 Object方法 的类型。
简单记忆 :除了 undefined 和 null 的任何值。
由于限制的范围实在 太大了 !所以实际开发中使用 频率极低

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let b: Object    // b 能存储的类型是 可以调用到 Object方法 的类型

class Person { }
b = new Person()

b = {}
b = { name: 'why' }
b = [1, 3, 5, 7, 9]
b = function () { }
b = new String('why')

b = 1
b = true
b = 'why'
b = null // (调用不到 Object方法 ) 警告:不能将类型“null”分配给类型“object”。
b = undefined // (调用不到 Object方法 ) 警告:不能将类型“undefined”分配给类型“object”。

声明对象类型

①、实际开发总,限制一般对象,通常使用以下形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 限制 person1 对象必须有 name 属性,age 为 可选属性
let person1: { name: string, age?: number };

// 含义同上,也能用分号做分隔
let person2: { name: string; age?: number };

// 含义同上,也能用换行做分隔
let person3: {
name: string
age?: number
};

// 如下赋值均可以
person1 = { name: 'Tom' };
person2 = { name: 'Tom', age: 18 };
person3 = { age: 18, name: 'Tom' };

// 如下赋值不合法,因为 person3 的类型限制中,没有对 gender 属性的声明
person3 = { name: 'Tom', age: 18, gender: 'male' };

②、 索引签名 : 允许定义对象可以具有 任意数量的属性 ,这些属性的 类型可变的 ,常用于:描述类型不确定的属性,(具有动态属性的对象)。

1
2
3
4
5
6
7
8
9
let person3: {
name: string
age?: number
[key: string]: any // key 可以是任意字符串,存储的类型是 any
};

person3 = { age: 18, name: 'Tom' };

person3 = { name: 'Tom', age: 18, gender: 'male' };

声明函数类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// let count: (参数1: <类型>, 参数1: <类型>) => <返回值类型> {}

let count: (asdasdads: number, dasafsfasb: number) => number; // 做好声明

// 后续会自动校验
// count = function (x, y) {
// return x + y + '222'
// }

// count = function (x, y) {
// return x + y
// }

count = (x, y) => {
return x + y
}

备注:

  • TypeScript 中的 =>在函数类型声明时表示 函数类型 ,描述其 参数类型返回类型

  • JavaScript 中的 =>是一种定义函数的语法,是具体的的数实现。

  • 函数类型声明还可以使用:接口、自定义类型等方式,下文中会详细讲解。

声明数组类型

1
2
3
4
5
6
let arr: string[];
// arr = ["a", "b", "c",123];

// 泛型 <> 指定 数组类型
let arr2 : Array<number>;
arr2 = [1,2,123];

备注: 上述代码中的 Array属于泛型,下文会详细讲解。

6、tuple

元组(Tuple)是一种特殊的 数组类型 ,可以存储 固定数量 的元素,并且每个元素的类型是 已知的可以不同 ,元组用于精确描述一组值的类型,?表示可选的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
// let a: tuple // 警告:找不到名称“tuple”。  它不是一个关键字

// [string, number] 就是元组,且 存储元素位置的类型 应 对应声明的一致
// let arr1: [string, number] = [2, '1'] // 警告:类型的参数不能赋值不对应的声明类型。
// let arr1: [string, number] = ['1', 1]

// 元组 number 类型可以包含可选元素
// let arr2: [string, number?];
// arr2 = ['1'];
// arr2 = ['1', 1];

// ...string[] 表示剩余参数,后面可以有任意多个 string 类型
let arr3: [boolean, number, ...string[]] = [true, 1, 'asddsadas', 'asdadsasdads'];

7、enum

枚举(enum) 可以定义 一组命名常量 ,它能增强代码的 可读性 ,也让代码 更好维护

如下代码的功能是:根据调用 walk 时传入的不同参数,执行不同的逻辑,存在的问题是调用 walk 时传参时没有任何提示,编码者很容易写错字符串内容;并且用于判断逻辑的up、down、left、right 是 连续且相关的一组值 ,那此时就特别适合使用 枚举(enum )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const walk = (str: string): void => {
if(str === 'up'){
console.log('向【上】走');
}else if(str === 'down'){
console.log('向【下】走');
}else if(str === 'left'){
console.log('向【左】走');
}else if(str === 'right'){
console.log('向【右】走');
}else{
console.log('未知方向');
}
}
walk('up');
walk('down');
walk('left');
walk('right');

数字枚举

数字枚举一种最常见的枚举类型,其成员的值会 自动递增 ,且数字枚举还具备 反向映射 的特点,在下面代码的打印中,不难发现:可以通过 来获取对应的枚举 成员名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
enum Direction{
// 默认从0开始
Up = 5,
Down = 12,
Left, // 以顺序最后的值开始递增 这里就是 13
Right // 这里就是 14
}

function walk(str: Direction) {
console.log(str);
if (str === Direction.Up) {
console.log("向【上】走");
}else if (str === Direction.Down) {
console.log("向【下】走");
}else if (str === Direction.Left) {
console.log("向【左】走");
}else if (str === Direction.Right) {
console.log("向【右】走");
}else {
console.log("无效的参数");
}
}

walk(Direction.Left);

字符串枚举

枚举成员的值是字符串。 注意:这里就没有反向映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
enum Direction{
Up = 'up',
Down = 'down',
Left = 'left',
Right = 'right'
}

function walk(str: Direction) {
console.log(str);
if (str === Direction.Up) {
console.log("向【上】走");
}else if (str === Direction.Down) {
console.log("向【下】走");
}else if (str === Direction.Left) {
console.log("向【左】走");
}else if (str === Direction.Right) {
console.log("向【右】走");
}else {
console.log("无效的参数");
}
}

常量枚举

官方描述:常量枚举是一种特殊枚举类型,它 使用 const 关键字定义 ,在编译时会 内联,避免 生成一些额外的代码。

何为编译时内联?
所谓“内联”其实就是 TypeScript 在编译时,会将枚举 成员引用 替换为它们的 实际值 ,而不是生成额外的枚举对象。这可以减少生成的 JavaScript 代码量,并提高运行时性能。

使用普通枚举的TypeScript效果如下:

常量枚举后,效果如下:

8、type

type 可以为任意类型创建别名,让代码更简洁、可读性更强,同时能更方便地进行类型复用和扩展。

基本用法:

类型别名使用 type 关键字定义,type 后跟类型名称,例如下面代码中 Num 是类型别名。

1
2
3
4
5
type Num = number;
function printNum(num: Num) :void{
console.log(num);
}
printNum(200);

联合类型:

联合类型是一种高级类型,它表示一个值可以是几种不同类型之一。 (简单理解:或 概念)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Status = number | string;
type gender = 'male' | 'female';
function printStatus(status: Status) :void{
console.log(status);
}

function printGender(gender: gender) :void{
console.log(gender);
}

printStatus(200);
printStatus('string');

printGender('male');
printGender('female');

交叉类型

交叉类型(Intersection Types):允许将多个类型合并为一个类型。合并后的类型将拥有所有被合并类型的成员。交又类型通常用于对象类型。 (简单理解:“ 并且and ” 概念)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
type Area = {
hight: number,
width: number
}

type Address = {
num: number // 楼号
cell: number // 单元号
room: string // 房间号
}

type House = Address & Area

const house: House = {
hight: 10,
width: 20,
num: 3,
cell: 4,
room: 'B-324'
}

type Demo = number & string
// Demo 无法成为值,它是 never 类型
let x: Demo;

9、特殊情况

情况1: 在函数定义时,限制函数返回值为 void ,那么函数的返回值就必须是空 或 undefined

1
2
3
4
5
6
7
8
9
10
11
// 注意书写习惯,当函数返回值为 空 的时候,加上 void 限制
function demo(): void{
return;
return undefined;

// 以下代码均不合法
// return 100;
// return true;
// return "hello world";
// return null;
}

情况2(特殊):

使用 类型声明 限制函数返回值为 void 时, Typescript 并不会严格要求函数返回空。

1
2
3
4
5
6
7
8
9
type LogFunc = () => void;  // 函数声明,只是声明,并没有变量
// 所以这里报错了
// LogFunc = function () { }

// 有了变量后声明是哪个函数表达式
const f1: LogFunc = function () {
// 特殊情况出现了:校验无效,允许返回
return 999
}

为什么会这样?

是为了确保如下代码成立,我们知道Array.prototype.push的返回一个数字,而Array.prototype.forEach 方法期望其回调的返回类型是 void

1
2
3
4
5
6
7
8
9
const src = [1, 2, 3]
const dst = [0]

// forEach 里面的匿名箭头函数 最后返回值是 dst.push(el)
src.forEach((el) => dst.push(el))

src.map((item) => { return item + 1 })

src.find((item) => { return item > 1 })

官方解释文档: TypeScript: Documentation - More on Functions

10、复习类相关知识

本小节是复习类相关知识,如果有相关基础可以跳过。这里的类知识跟 Java 的类知识基本一致。

class类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person{
// 类属性
private name: string
// 类构造器
constructor(name: string) {
this.name = name
}
// 类方法
public speak(){
console.log(`Hi, I am ${this.name}`)
}
public getName(){
return this.name
}
}
const p1 = new Person('Angindem')
p1.speak();

继承类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Person{
// 类属性
private name: string
// 类构造器
constructor(name: string) {
this.name = name
}
// 类方法
public speak(){
console.log(`Hi, I am ${this.name}`)
}

public getName(){
return this.name
}
}
// const p1 = new Person('Angindem')
// p1.speak();

// 继承 Person 类
class Student extends Person{

private age: number
// 继承父类的构造器
constructor(name: string, age: number) {
super(name);
this.age = age
}
public study(){
console.log(`I am studying`)
}

// override 重写符号,对这个方法进行了覆盖重写
override speak(){
console.log(`I am ${this.getName()} and I am ${this.age} years old`)
}
}

const s1 = new Student('Angindem', 18)
s1.study()
s1.speak()

11、属性修饰符

修饰符 含义 具体规则
public 公开的 可以被: 类内部、子类、类外部 访问。
protected 受保护的 可以被: 类内部、子类 访问。
private 私有的 可以被: 类内部 访问。
readonly 只读属性 属性无法修改

注意点:Script中 class 类内部没有指定属性修饰符的时候默认是 public

简写构造器

1
2
3
4
5
6
class Person{
// 简写构造器,构造同时声明属性
constructor(public name:string,public age:number){}
}
const p1 = new Person('张三', 18);
console.log(p1.name);

12、抽象类

概述:抽象类是 无法被实例化 的类,专门用来定义类的 结构和行为 ,类中可以写 抽象方法 ,也可以写 具体实现 。抽象类主要用来为其派生类提供一个 基础结构 ,要求其派生类 必须实现 其中的抽象方法。
简记:抽象类 不能实例化 ,其意义是 可以被继承 ,抽象类里可以有 普通方法 、也可以有 抽象方法

通过以下场景,理解抽象类:

我们定义一个抽象类 Package ,表示所有包裏的基本结构,任何包裏都有重量属性 weight ,包裏都需要计算运费。但不同类型的包裹(如:标准速度、特快专递)都有不同的运费计算方式,因此用于计算运费的 calculate 方法是一个抽象方法,必须由具体的子类来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 定义抽象类
abstract class Package {
// 构造方法
constructor(public weight:number) {
}

// 抽象方法
abstract calculateCost(): number

// 具体方法
printPackageInfo() {
console.log(`包裹的重量为 ${this.weight} kg,运费为 ${this.calculateCost()} 元`);
}
}

class StandardPackage extends Package {
constructor(
weight: number,
public unitPrice: number
) {
super(weight);
}

// 实现抽象方法
calculateCost(): number {
return this.weight * 0.5 * this.unitPrice;
}
}

const s1 = new StandardPackage(5, 4);
s1.printPackageInfo();

总结:何时使用 抽象类 ?
定义通用接口 :为一组相关的类定义通用的行为(方法或属性)时。
提供基础实现 :在抽象类中提供某些方法或为其提供基础实现,这样派生类就可以继承这些实现。
确保关键实现 :强制派生类实现一些关键行为。
共享代码和逻辑 :当多个类需要共享部分代码时,抽象类可以避免代码重复。

13、接口

interface 是一种 定义结构 的方式,主要作用是为:类、对象、函数等规定 一种契约 ,这样可以确保代码的一致性和类型安全,但要注意 interface 只能 定义 格式 ,不能包含 任何实现 !

定义 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
interface PersonInterface {
name: string;
speak(n:number): void;
}

class Person implements PersonInterface {
constructor(public name:string){}
speak(n: number): void {
for(let i = 0; i < n; i++){
console.log(`${this.name} says hello!`);
}
}
}

const p = new Person('Angindem');
p.speak(5);

定义 对象 结构

1
2
3
4
5
6
7
8
interface CountInterface {
(a: number, b: number): number;
}

// 接口限制函数参数和返回值类型
const count: CountInterface = (a: number, b: number): number => {
return a + b;
};

定义 函数 结构

1
2
3
4
5
6
7
8
interface CountInterface {
(a: number, b: number): number;
}

// 接口限制函数参数和返回值类型
const count: CountInterface = (a: number, b: number): number => {
return a + b;
};

接口之间的继承

interface继承另一个interface,从而实现代码的复用

1
2
3
4
5
6
7
8
9
10
interface PersonInterface {
name: string;
age: number;
}

interface StudentInterface extends PersonInterface {
grade: string;
}

const stu:StudentInterface = {name: '张三', age: 18, grade: 'A'};

接口自动合并(可重复定义)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface PersonInterface {
name: string;
age: number;
}

interface PersonInterface {
gender: string;
}

const p: PersonInterface = {
name: '张三',
age: 18,
gender: '男'
}

总结:何时使用接口?

  • 定义对象的格式 :描述数据模型、API 响应格式、配置对象!..等等,是开发中用的最多的场景。

  • 类的契约 :规定一个类需要实现哪些属性和方法。

  • 自动合并 :一般用于扩展第三方库的类型,这种特性在大型项目中可能会用到。

14、一些相似概念的区别

14.1  interface 与 type 区别

相同点 :interface 和 type都可以用于定义 对象结构 ,两者在许多场景中是可以互换的。
不同点:

  1. interface:更专注于定义 对象 的结构,支持 继承、合并

  2. type:可以定义 类型别名、联合类型、交叉类型 ,但不支持继承和自动合并。

  • interface 和 type 都可以定义对象结构

  • interface 可以继承、合并

  • type 的交叉类型

14.2 interface 与 抽象类的区别

相同点 :都用于定义一个 类的格式 (应该遵循的契约)
不相同

  1. 接口: 只能 描述 结构不能 有任何 实现代码 ,一个类可以实现多个接口。

  2. 抽象类:既可以包含 抽象方法 ,也可以包含 具体方法 ,一个类只能继承一个抽象类。

  • 一个类 可以 实现多个接口

八、泛型

泛型允许我们在定义函数、类或接口时,使用类型参数来表未 指定的类型 ,这些参数在具体 使用时 才被指定 具体的类型 ,泛型能让同一段代码适用于多种类型,同时仍然保持类型的安全性。

举例:如下代码中就是泛型,(不一定非叫 T),设置泛型后即可在函数中使用 T来表示该类型:

泛型函数

1
2
3
4
5
6
7
8
// 泛型函数
function logData<T>(data: T): T{
console.log(data);
return data
}

logData<string>('hello world');
logData<number>(123);

泛型可以有多个

1
2
3
4
5
6
7
function logData<T, U>(data1: T, data2: U): T | U {
Date.now() % 2 ? console.log(data1) : console.log(data2);
return Date.now() % 2 ? data1 : data2;
}

logData<string,boolean>('hello world',true);
logData<number,boolean>(123,true);

泛型接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
interface PersonInterface<T>{
name: string;
age: number;
extraInfo: T;
}

type Job = {
jobTitle: string;
salary: number;
}

let p : PersonInterface<Job> = {
name: 'Jane',
age: 25,
extraInfo: {
jobTitle: 'Software Developer',
salary: 50000
}
}

泛型类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person<T>{
constructor(
public name: string,
public age: number,
public extraInfo: T
) { }
speak() {
console.log(`${this.name} is ${this.age} years old`)
console.log(this.extraInfo);
}
}

type Job = { job: string };

const p1 = new Person<string>('Mike', 20, 'I am a string');
p1.speak();

const p2 = new Person<Job>('Mike', 20, { job: 'Software Engineer' });
p2.speak();

九、类型声明文件(.d.ts)

类型声明文件是 TypeScript 中的一种特殊文件,通常以.d.ts 作为扩展名。它的主要作用是为现有的 JavaScript 代码提供类型信息,使得 TypeScript 能够在使用这些 JavaScript 库或模块时进行类型检查和提示。

一般项目中都会在 types 文件夹中。

假设有demo.js

1
2
3
4
5
6
export function add(a, b) {
return a + b;
}
export function mul(a, b) {
return a * b;
}

然后我们 ts 引入

原因:引入的 JS 默认为 any ,爆出警告,所以我们需要类型声明文件

1
2
3
4
5
6
7
8
9
10
//  demo.d.ts

// declare : 声明
declare function add(a: number, b: number): number;
declare function mul(a: number, b: number): number;

export {
add,
mul
};


觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭

微信二维码

wechat pay

支付宝二维码

ali pay

一天速通TypeScript入门基础知识
http://blog.angindem.cn/2025/07/13/Angindem-CSDN博客/184_184/
作者
Angindem
发布于
2025年7月13日
许可协议