TypeScript 速通
1.类型声明
let a: string; //变量a只能存储字符串
let b: number; //变量a只能存储数值
let c: boolean; //变量a只能存储布尔值
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
包含Array
、Function
、Date
TypeScript
中的数据类型:
- 以上都有
- 四个新类型:
void
、never
、unknown
、any
、enum
、tuple
- 自定义类型:
type
、interface
注意
JS
中的这三个构造函数:Number
、String
、Boolean
,他们只⽤于包装对象,正常开发时,很少去使⽤他们,在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 | 布尔值 true 或 false | true 、 false |
字⾯量 | 值只能是字⾯量值 | 值本身 |
any | 任意类型 | 1 、 'hello' 、 true .... |
unknown | 类型安全的 any | 1 、 'hello' 、 true .... |
never | 不能是任何值 | ⽆值 |
void | 空 或 undefined | 空 或 undefined |
object | 任意的 JS 对象 | {name:'张三'} |
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
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
的含义是:任何值都不是,简⾔之就是不能有值,undefined
、null
、''
、0
都不行!
- 几乎不用
never
去直接限制变量,因为没有意义,例如:
/* 指定a的类型为never,那就意味着a以后不能存任何的数据了 */
let a: never
// 以下对a的所有赋值都会有警告
a = 1
a = true
a = undefined a = null
never
一般是TypeScript
主动推断出来的,例如:
// 指定a的类型为string
let a: string;
// 给a设置⼀个值
a = "hello";
if (typeof a === "string") {
a.toUpperCase();
} else {
console.log(a); // TypeScript会推断出此处的a是never,因为没有任何⼀个值符合此处的逻辑
}
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
关于
Object
与object
,直接说结论:在类型限制时,Object
几乎不用,因为范围太大了,无意义。
object
的含义:任何【非原始值类型】,包括:对象、函数、数组等,限制的范围比较宽泛,用的少。
let a: object; //a的值可以是任何【⾮原始值类型】,包括:对象、函数、数组等
// 以下代码,是将【⾮原始类型】赋给a,所以均⽆警告
a = {};
a = { name: "张三" };
a = [1, 3, 5, 7, 9];
a = function () {};
// 以下代码,是将【原始类型】赋给a,有警告
a = null; // 警告:不能将类型“null”分配给类型“object”
a = undefined; // 警告:不能将类型“undefined”分配给类型“object” a = 1 // 警告:不能将类型“number”分配给类型“object”
a = true; // 警告:不能将类型“boolean”分配给类型“object”
a = "你好"; // 警告:不能将类型“string”分配给类型“object”
Object
的含义:Object
的实例对象,限制的范围太大了,几乎不用。
let a: Object; //a的值必须是Object的实例对象,
// 以下代码,均⽆警告,因为给a赋的值,都是Object的实例对象
a = {};
a = { name: "张三" };
a = [1, 3, 5, 7, 9];
a = function () {};
a = 1; // 1不是Object的实例对象,但其包装对象是Object的实例
a = true; // true不是Object的实例对象,但其包装对象是Object的实例
a = "你好"; // “你好”不是Object的实例对象,但其包装对象是Object的实例
// 以下代码均有警告
a = null; // 警告:不能将类型“null”分配给类型“Object”
a = undefined; // 警告:不能将类型“undefined”分配给类型“Object”
- 实际开发中,限制一般对象,通常使用以下形式
// 限制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: "红⾊" };
student = { id: "tetqw76te01", grade: 3 };
- 限制函数的参数、返回值,使用以下形式
let demo: (a: number, b: number) => number;
demo = function (x, y) {
return x + y;
};
- 限制数组,使用以下形式
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: [string, number];
t = ["hello", 123];
// 警告,不能将类型“[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: "iPhone15Pro", 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 };
6.类
常规类
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const p1 = new Person("张三", 18);
const p2 = new Person("李四", 19);
console.log(p1);
console.log(p2);
继承:
// Person类
class Person {…}
// Teacher类继承Person
class Teacher extends Person {…}
// Student类继承Person
class Student extends Person {…}
// Person实例
const p1 = new Person('周杰伦 ',38)
// Student实例
const s1 = new Student('张同学 ',18)
const s2 = new Student('李同学 ',20)
// Teacher实例
const t1 = new Teacher('刘老师 ',40)
const t2 = new Teacher('孙老师 ',50)
抽象类
抽象类不能去实例化,但可以被别人继承,抽象类里有抽象方法
// Person(抽象类)
abstract class Person {…}
// Teacher类继承Person
class Teacher extends Person {
// 构造器
constructor(name: string,age: number){
super(name,age)
}
// ⽅法
speak(){
console.log('你好!我是⽼师:',this.name)
}
}
// Student类继承Person
class Student extends Person {……}
// Person实例
// const p1 = new Person('周杰伦',38) // 由于Person是抽象类,所以此处不可以new Person的实例对象
7.接口
接口梳理:
- 接口用于限制一个类中包含哪些属性和方法:
// Person接⼝
interface Person {
// 属性声明
name: string;
age: number;
// ⽅法声明
speak(): void;
}
// Teacher实现Person接⼝
class Teacher implements Person {
name: string;
age: number;
// 构造器
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// ⽅法
speak() {
console.log("你好!我是⽼师:", this.name);
}
}
- 接口是可以重复声明的:
// Person接⼝
interface PersonInter {
// 属性声明
name: string;
age: number;
}
// Person接⼝
interface PersonInter {
// ⽅法声明
speak(): void;
}
// Person类继承PersonInter
class Person implements PersonInter {
name: string;
age: number;
// 构造器
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// ⽅法
speak() {
console.log("你好!我是⽼师:", this.name);
}
}
- 【接口】与【自定义类型】的区别:
建议
接口可以:
- 当自定义类型去使用;
- 可以限制类的结构;
自定义类型:仅仅就是自定义类型;
// Person接⼝
interface Person {
// 应该具有的属性
name: string;
age: number;
// 应该具有的⽅法
speak(): void;
}
// Person类型
/*
type Person = {
// 应该具有的属性
name: string age: number
// 应该具有的⽅法
speak():void
}
*/
// 接⼝当成⾃定义类型去使⽤
let person: Person = {
name: "张三",
age: 18,
speak() {
console.log("你好!");
},
};
4.【接口】与【抽象类】的区别:
建议
抽象类:
可以有普通方法,也可以有抽象方法;
使用 extends 关键字去继承抽象类;
接口中:
只能有抽象方法;
使用 implements 关键字去实现接口
抽象类举例
// 抽象类 —— Person
abstract class Person {
// 属性
name: string;
age: number;
// 构造器
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// 抽象⽅法
abstract speak(): void;
// 普通⽅法
walk() {
console.log("我在⾏⾛中");
}
}
// Teacher类继承抽象类Person
class Teacher extends Person {
constructor(name: string, age: number) {
super(name, age);
}
speak() {
console.log(`我是⽼师,我的名字是${this.name}`);
}
}
接口举例:
// 接⼝ —— Person,只能包含抽象⽅法
interface Person {
// 属性,不写具体值
name: string;
age: number;
// ⽅法,不写具体实现
speak(): void;
}
// 创建Teacher类实现Person接⼝
class Teacher implements Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
speak() {
console.log("我在⻜快的⾏⾛中");
}
}
8.属性修饰符
readonly | 只读属性 | 属性⽆法修改 |
---|---|---|
public | 公开的 | 可以在类、⼦类和对象中修改 |
protected | 受保护的 | 可以在类、⼦类中修改 |
private | 私有的 | 可以在类中修改 |
9.泛型
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时就需要泛型了 举例: <T>
就是泛型,(不一定非叫 T
),设置泛型后即可在函数中使用 T
来表示该类型:
function test<T>(arg: T): T {
return arg;
}
// 不指名类型,TS会⾃动推断出来
test(10);
// 指名具体的类型
test<number>(10);
泛型可以写多个:
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;
}
test(10); // 类型“number”的参数不能赋给类型“Demo”的参数
test({ name: "张三" }); // 类型“{ name: string; }”的参数不能赋给类型“Demo”的参数
test("123");
test({ name: "张三", length: 10 });