Skip to main content

Typesecirpt 极速梳理

1.类型声明

let a: string // 变量a只能存储字符串
let b: number // 变量b只能存储数值
let c: boolean // 变量c只能存储布尔值

a = 'hello'
a = 100 // 警告:不能将类型“number”分配给类型“string”

b = 666
b = '你好'// 警告:不能将类型“string”分配给类型“number”

c = true
c = 666 // 警告:不能将类型“number”分配给类型“boolean”

// 参数x必须是数字,参数y也必须是数字,函数返回值也必须是数字
function demo(x:number,y:number):number{
return x + y
}

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

2.类型推断

let d = -99 // TypeScript会推断出变量d的类型是数字
d = false // 警告:不能将类型“boolean”分配给类型“number”

3.类型总览

JavaScript 中的数据类型:

  • string
  • number
  • boolean
  • null
  • undefined
  • bigint
  • symbol
  • object

备注:其中 object 包含:ArrayFunctionDate ......

TypeScript 中的数据类型:

  • 1、以上所有
  • 2、四个新类型:voidneverunknownanyenumtuple
  • 3、自定义类型:typeinterface

注意点:JS 中的这三个构造函数:NumberStringBoolean,它们只用于包装对象,正常开发时,很少去使用它们,在 TS 中也是同理。

let n = 56
n.toFixed(2)

/*
当执⾏n.toFixed(2) ,底层做了这⼏件事:
1.let temp = new Number(42)
2.value = temp.toFixed(2)
3.删除value
4.返回value
*/

类型总览:

类型描述举例
number任意数字1,-33,2.5
string任意字符串'hello','ok','你好'
boolean布尔值 truefalsetrue、false
字面量值只能是字面量值值本身
any任意类型1,'hello',true......
unknown类型安全的 any1、'hello',true......
never不能是任何值无值
voidundefinedundefined
object任意的 JS 对象{name: 'zhangsan'}
tuple元素,TS 新增类型,固定长度数组[4, 5]
enum枚举,TS 中新增类型enum{A, B}

4.常用类型

4.1.字面量

let a: '你好' //a的值只能为字符串“你好”
let b: 100 //b的值只能为数字100

a = '欢迎'//警告:不能将类型“"欢迎"”分配给类型“"你好"”
b = 200 //警告:不能将类型“200”分配给类型“100”

let gender: '男'|'⼥' //定义⼀个gender变量,值只能为字符串“男”或“⼥”
gender = '男'
gender = '未知' //不能将类型“"未知"”分配给类型“"男" | "⼥"”

4.2.any

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

//明确的表示a的类型是any —— 显式的any
let a: any
//以下对a的赋值,均⽆警告
a = 100
a = '你好'
a = false

//没有明确的表示b的类型是any,但TS主动推断了出来 —— 隐式的any
let b
//以下对b的赋值,均⽆警告
b = 100
b = '你好'
b = false

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

/* 注意点:any类型的变量,可以赋值给任意类型的变量 */
let a // TS 会自动推断出 a 的类型是 any
let x: string
x = a // 无警告

4.3.unknown

unknown 的含义是:未知类型。

备注1:unknown 可以理解为一个类型安全的 any

备注2:unknown 适用于:开始不知道数据的具体类型,后期才能确定数据的类型。

// 设置 a 的类型为 unknown
let a: unknown

// 以下对 a 的赋值,均正常
a = 100
a = false
a = '你好'

// 设置 x 的数据类型为 string
let x: string
x = a // 警告:不能将类型“unknown”分配给类型“string”

若就是想把 a 赋值给 x,可以用以下三种写法:

// 设置 a 的类型为 unknown
let a: unknown
a = 'hello'

// 第一种方式:加类型判断
if (typeof a === 'string') {
x = a
}

// 第二种方式:加断言
x = a as string

// 第三种方式:加断言
x = <string>a

any 后点任何的东西都不会报错,而 unknown 正好与之相反。

let str1: string = 'hello'
str1.toUpperCase() // 无警告

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

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

// 使用断言强制指定 str3 的类型为 string
(str3 as string).toUpperCase() // 无警告

4.4.never

never 的含义是:任何值都不是,简言之就是不能有值,undefinednull''0 都不行。

  1. 几乎不用 never 去直接限制变量,因为没有意义,例如:
/* 指定 a 的类型为 never,那就意味着 a 以后不能存任何的数据了 */
let a: never

// 以下对 a 的所有赋值都会有警告
a = 1
a = true
a = undefined
a = null
  1. never 一般是 TypeScript 主动推断出来的,例如:
// 指定 a 的类型为 string
let a: string
// 给 a 设置一个值
a = 'hello'

if(typeof a === 'string'){
a.toUpperCase()
}else{
console.log(a) // TypeScript 会推断出此处的 a 是never,因为没有任何一个值符合此处的逻辑
}
  1. never 也可用于限制函数的返回值:
// 限制 demo 函数不需要有任何返回值,任何值都不行,像 undefined、null都不行
function demo(): never {
throw new Error('程序异常退出')
}

4.5.void

void 的含义是:undefined,严格模式下不能将 null 赋值给 void 类型。

let a: void = undefined

// 严格模式下,该行会有警告:不能将类型 "null" 分配给 类型 "void"
let b: void = null

void 常用于限制函数返回值

// 无警告
function demo1(): void{

}

// 无警告
function demo2(): void{
return
}

// 无警告
function demo3(): void{
return undefined
}

// 有警告:不能将类型"number"分配给类型"void"
function demo4(): void{
return 666
}

4.6.object

关于 Objectobject,直接说结论:在类型限制时,Object 几乎不用,因为范围太大了,无意义。

  1. object 的含义:任何 【非原始值类型】,包括:对象、函数、数组等,限制的范围比较宽泛,用的少。
let a: object // a 的值可以是任何【非原始值类型】,包括:对象、函数、数组等

// 以下代码,是将 【非原始值类型】赋给 a,所以均无警告
a = {}
a = {name: 'zhangsan'}
a = [1, 3, 5]
a = function(){}

// 以下代码,是将 【原始值类型】 赋给 a,有警告
a = null // 警告:不能将类型“null”分配给类型“object”
a = undefined // 警告:不能将类型“undefined”分配给类型“object”
a = 1 // 警告:不能将类型“number”分配给类型“object”
a = true // 警告:不能将类型“boolean”分配给类型“object”
a = 'nihao' // 警告:不能将类型“string”分配给类型“object”
  1. Object 的含义:Object 的实例对象,限制的范围太大了,几乎不用。
let a: Object // a 的值必须是 Object 的实例对象

// 以下代码,均无警告,因为给 a 赋的值,都是 Object 的实例对象
a = {}
a = [1, 3, 5]
a = function() {}
a = 1 // 1不是Object的实例对象,但其包装对象是Object的实例
a = true // truue不是Object的实例对象,但其包装对象是Object的实例
a = '你好' // “你好”不是Object的实例对象,但其包装对象是Object的实例

// 以下代码均有警告
a = null // 警告:不能将类型"null"分配给类型"Object"
a = undefined // 警告:不能将类型"undefined"分配给类型"Object"
  1. 实际开发中,限制一般对象,通常使用以下形式。
// 限制 person 对象的具体内容,使用 【,】 分割,问号代表可选属性
let person: {name: string, age?: number}

// 限制 car 对象的具体内容,使用 【;】分割,必须有 price 和 color 属性,其它属性不去限制,有没有都行
let car: {price: number; color: string; [k: string]: any}

// 限制 student 对象的具体内容,使用 【回车】分割
let student: {
id: string
grade: number
}

// 以下代码均无警告
person = {name: '张三', age: 18}
person = {name: '张三'}
car = {price: 100, color: '红色'}
car = {price: 100, color: '红色', size: '大号'}
// 等价于下面这行
car = {"price": 100, "color": '红色', "size": '大号'}
student = {id: 'teaf2', grade: 3}
  1. 限制函数的参数、返回值,使用以下形式
let demo: (a: number, b: number) => number

demo = function(x, y) {
return x + y
}
  1. 限制数组,使用以下形式
let arr1: string[] // 该行代码等价于:let arr1: Array<string>
let arr2: number[] // 该行代码等价于:let arr2: Array<number>

arr1 = ['a', 'b', 'c']
arr2 = [1, 3, 5, 7, 9]

4.7.tuple

tuple 就是一个长度固定的数组。

let t: [striing, number]

// 警告,不能将类型“[string, number, boolean]”分配给类型“[string, number]”
t = ['hello',123,false]

4.8.enum

enum 是枚举

// 定义一个枚举
enum Color{
Red,
Blue,
Black,
Gold
}

// 定义一个枚举,并指定其初始数值
enum Color2{
Red = 6,
Blue,
Black,
Gold
}

console.log(Color)
/*
{
'0': 'Red',
'1': 'Blue',
'2': 'Black',
'3': 'Gold',
Red: 0,
Blue: 1,
Black: 2,
Gold: 3
}
*/

console.log(Color2)
/*
{
'6': 'Red',
'7': 'Blue',
'8': 'Black',
'9': 'Gold',
Red: 6,
Blue: 7,
Black: 8,
Gold: 9
}
*/

// 定义一个 phone 变量,并对其进行限制
let phone: {name: string, price: number, color: Color}

phone= {name: '华为Mate60', price: 6500, color: Color.Red}

phone= {name: 'iPhone16Pro', price: 7999, color: Color.Blue}

if(phone.color === Color.Red) {
console.log('手机是红色的')
}

5.自定义类型

自定义类型,可以更灵活的限制类型

// 性别的枚举
enum Gender {
Male,
Female
}

// 自定义一个年级类型(高一、高二、高三)
type Grade = 1 | 2 | 3

// 自定义一个学生类型
type Student = {
name: string,
age: number,
gender: Gender,
grade: Grade
}

// 定义两个学生变量: s1, s2
let s1: Student
let s2: Student

s1 = {name: '张三', age: 18, gender: Gender.Male, grade: 1}
s2 = {name: '李四', age: 18, gender: Gender.Female, grade: 2}

console.log(s1) // { name: '张三', age: 18, gender: 0, grade: 1 }
console.log(s2) // { name: '李四', age: 18, gender: 1, grade: 2 }

6.抽象类

常规类:

class Person{
name: string
age: number

constructor(name: string, age: number){
this.name = name
this.age = age
}
}

const p1 = new Person("Alice", 30);
const p2 = new Person("Bob", 25);

console.log(p1) // Person { name: 'Alice', age: 30 }
console.log(p2) // Person { name: 'Bob', age: 25 }

继承:

// Person 类
class Person{
name: string
age: number

constructor(name: string, age: number){
this.name = name
this.age = age
}
}

// Teacher 类 继承 Person
class Teacher extends Person{
subject: string

constructor(name: string, age: number, subject: string){
super(name, age) // 调用父类构造函数
this.subject = subject
}
}

// Student 类 继承 Person
class Student extends Person{
grade: string

constructor(name: string, age: number, grade: string){
super(name, age) // 调用父类构造函数
this.grade = grade
}
}

// Person 实例
const p1 = new Person("Alice", 30);
// Teacher 实例
const t1 = new Teacher("Bob", 40, "Math");
// Student 实例
const s1 = new Student("Charlie", 20, "10th Grade");

// 打印实例信息
console.log(`Person: ${p1.name}, Age: ${p1.age}`);
// Person: Alice, Age: 30
console.log(`Teacher: ${t1.name}, Age: ${t1.age}, Subject: ${t1.subject}`);
// Teacher: Bob, Age: 40, Subject: Math
console.log(`Student: ${s1.name}, Age: ${s1.age}, Grade: ${s1.grade}`);
// Student: Charlie, Age: 20, Grade: 10th Grade

抽象类:不能去实例化,但可以被别人继承,抽象类里有抽象方法。

// Person (抽象类)
abstract class Person {
// 抽象属性只声明、不实现;
// 子类必须在自己的构造器或字段中明确声明并赋值;
// 抽象类本身不能实现抽象属性的初始化,否则违背“抽象”的定义。
name: string;
age: number;

constructor(name: string, age: number) {
this.name = name;
this.age = age;
}

abstract speak(): void;
}

// Teacher 类 继承 Person
class Teacher extends Person {
// 构造器
constructor(name: string, age: number){
super(name, age)
this.name = name
this.age = age
}

// 重写方法
speak(){
console.log('你好!我是老师: ', this.name)
}
}

// 调用示例
const teacher = new Teacher('张老师', 30);
teacher.speak(); // 输出: 你好!我是老师: 张老师

7.接口

接口梳理:

  1. 接口用于限制一个类中包含哪些属性和方法。
  2. 接口是可以重复声明的。
  3. 接口自定义类型 的区别:

接口可以:

1、当自定义类型去使用。

2、可以限制类的结构。

自定义类型:

1、仅仅就是自定义类型。

  1. 接口抽象类 的区别:

抽象类:

1、可以有普通方法,也可以有抽象方法。

2、使用 extends 关键字去继承抽象类。

接口:

1、只能有抽象方法。

2、使用 implements 关键字去实现接口。

抽象类举例:

// 抽象类 Animal
abstract class Animal {
constructor(public name: string) {}

// 抽象方法,子类必须实现
abstract makeSound(): void;

// 普通方法,子类可继承使用
move(): void {
console.log(`${this.name} 正在移动`);
}
}

// 子类 Dog
class Dog extends Animal {
makeSound(): void {
console.log(`${this.name} 汪汪叫`);
}
}

// 子类 Cat
class Cat extends Animal {
makeSound(): void {
console.log(`${this.name} 喵喵叫`);
}
}

// 使用示例
const dog = new Dog('旺财');
dog.makeSound(); // 旺财 汪汪叫
dog.move(); // 旺财 正在移动

const cat = new Cat('小花');
cat.makeSound(); // 小花 喵喵叫
cat.move(); // 小花 正在移动

// 抽象类不能被直接实例化
const animal = new Animal('某动物'); // ❌ 错误:抽象类不能被实例化

接口举例:

// 定义接口
interface User {
id: number;
name: string;
age?: number; // 可选属性
sayHello(): void; // 方法签名
}

// 使用接口的对象
const user1: User = {
id: 1,
name: '张三',
sayHello() {
console.log(`你好,我是 ${this.name}`);
}
};

user1.sayHello(); // 输出:你好,我是 张三

✅ 接口的主要特点

特点描述
可选属性? 修饰,表示该字段可有可无
只读属性readonly 修饰,表示不能修改
函数签名可以定义方法的形状
接口继承接口可以继承其他接口
接口 vs 类型别名接口只能描述对象结构,但更适合用来描述“行为约束”

✨ 接口继承示例:

interface Person {
name: string;
}

interface Student extends Person {
studentId: string;
}

const stu: Student = {
name: '小李',
studentId: 'S001'
};

8.属性修饰符

修饰符权限描述
readonly只读属性属性无法修改
public公开的可以在类、子类和对象中修改
protected受保护的可以在类、子类中修改
private私有的可以在类中修改

9.泛型

定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时就需要泛型了。

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

function test<T>(arg: T): T{
return arg;
}

// 不指定类型,TS会自动推断出来
test(10)

// 指定具体的类型
test<number>(20)

泛型可以写多个:

function test<T, K>(a: T, b: K): K {
return b;
}

// 为多个泛型指定具体值
test<number, string>(10, 'hello');

类中同样可以使用泛型:

class MyClass<T>{
prop: T;

constructor(prop: T){
this.prop = prop;
}
}

也可以对泛型的范围进行约束:

interface Demo{
length: number;
}

// 泛型 T 必须是 MyInter 的子类,即:必须拥有 length 属性
function test<T extends Demo>(arg: T): number{
return arg.length;
}

// error TS2345: Argument of type 'number' is not assignable to parameter of type 'Demo'.
// test(10)


// error TS2353: Object literal may only specify known properties, and 'name' does not exist in type 'Demo'.
// test({name: '张三'})

test('123')
test({name: '张三', length: 10})