文章目录

typescript系列教程
typescript 类型及使用
typescript 三种类修饰符
typescript抽象类 abstract
typescript接口 interface
typescript 泛型常见用法
typescript class可以作为类型定义被扩展
三分钟了解interface和type
typescript 模块化,命名空间
typescript 装饰器全集
数字 number (自然数,浮点数,负数)
let number1: number = 111222;
console.log(number1)
number1 = 12.3
console.log(number1)
number1 = -5
console.log(number1)
// 已经定义为number就不能再将其赋值其它类型
number1 = 'dx';
字符串类型 string
let str:string = "dx";
console.log(str)
//如果str定为字符串,就只能为其赋值字符串,赋值为number或其它类型会报错
str = 1
数组类型 array
// 空数组
let array1: [] = [];
// number数组 数组的元素必须全为number类型,否则会报错
let numberArray1: number[] = [1, 2, 3, 4, 5];
// numberArray1.push('dx')
numberArray1.push(2.4);
// 还有一种写法
let numberArray2: Array<number> = [1, 2, 3, 4, 5];
//字符串数组 数组的元素必须全为字符串类型,否则会报错
let stringArray: string[] = ['x', 'y'];
//对象数组 数组的元素必须全为对象,每个对象都必须有a属性,值为number
let objArray: {
a: number;
}[] = [{ a: 1 }];
元祖类型 tuple(用来规定数组中每一个元素的类型)
元祖是一种特殊的数组类型
// tuple元祖类型是数组类型的一种 限制数组的元素个数,
// 并且限制每一个元素的类型
let tupleArray: [string,number,object] = ['dx',3,{}]
// 当某个元素不确定是否存在时,这个不确定的元素一定要在必须元素的最后面
let tupleArray: [string,number,object?] = ['dx',3]
// 任意多个元祖,解构赋值的形式进行
let tupleArray1: [string,number,...string[]] = ['dx',3,'a','b','c']
// 只对数组元素的第一个和第二个起到限制作用,后面的不限制
let tupleArray2: [string,number,...any[]] = ['dx',3,'a',18,false]
枚举类型 enum
- 字符串枚举
// 枚举类型enum
enum Flag {
wait = '待支付',
success = '已支付',
error = '有内鬼,终止交易',
}
let EnumWait: Flag = Flag.wait;
console.log(EnumWait); //'待支付'
// 也可以直接一点
console.log(Flag.error);
// 不赋值的枚举,会默认赋值为数组的下标
enum Enum1 {
a,
b,
c,
}
let Enum1Value: Enum1 = Enum1.a;
console.log(Enum1Value); // 0
console.log(Enum1.b); // 1
//不全赋值枚举类型
enum Enum2 {
a = 2,
b,
c,
}
let Enum2Value: Enum2 = Enum2.a;
console.log(Enum2Value); // 2
console.log(Enum2.b); // 3
// 会报错的部分枚举, 不能不赋值枚举的类型,除非它上一个没有被赋值或者赋值为number类型
// enum Enum3 {
// a = 'dx',
// b,
// c,
// }
// 不会报错的部分枚举
enum Enum4 {
a = 1,
b,
c,
}
enum Enum5 {
a = 'dx',
b = 1,
c,
}
- 数字枚举一种最常见的枚举类型,其成员的值会自动递增,且数字枚举还具备反向映射的特点,在下面代码的打印中,不难发现:可以通过值来获取对应的枚举成员名称 。
使用数字枚举完成walk函数中的逻辑,此时我们发现: 代码更加直观易读,而且类型安全,同时也更易于维护。
enum Direction {
Up,
Down,
Left,
Right,
}
function walk(n: Direction) {
if (n === Direction.Up) {
console.log("向【上】走");
} else if (n === Direction.Down) {
console.log("向【下】走");
} else if (n === Direction.Left) {
console.log("向【左】走");
} else if (n === Direction.Right) {
console.log("向【右】走");
} else {
console.log("未知方向");
}
}
walk(Direction.Up)
walk(Direction.Down)
- 常量枚举
官方描述:常量枚举是一种特殊枚举类型,它使用const关键字定义,在编译时会被内联,避免生成一些额外的代码。
何为编译时内联?
所谓“内联”其实就是 TypeScript 在编译时,会将枚举成员引用替换为它们的实际值,而不是生成额外的枚举对象。这可以减少生成的 JavaScript 代码量,并提高运行时性能。
使用普通枚举的 TypeScript 代码如下:
enum Directions {
Up,
Down,
Left,
Right
}
let x = Directions.Up;
编译后生成的 JavaScript 代码量较大 :
"use strict";
var Directions;
(function (Directions) {
Directions[Directions["Up"] = 0] = "Up";
Directions[Directions["Down"] = 1] = "Down";
Directions[Directions["Left"] = 2] = "Left";
Directions[Directions["Right"] = 3] = "Right";
})(Directions || (Directions = {}));
let x = Directions.Up;
使用常量枚举的 TypeScript 代码如下:
const enum Directions {
Up,
Down,
Left,
Right
}
let x = Directions.Up;
编译后生成的 JavaScript 代码量较小:
"use strict";
let x = 0 /* Directions.Up */;
任意类型 any
// 任意类型 any, 不再受到类型的限制,想怎么赋值就怎么赋值
// 当你不知道某个变量的类型时,可以设置为any
let any1:any = 1
any1 = 'dx'
let any2:any = ''
any2 = 2
let any3:any = {}
let any4:any = function() {}
let any5:any = []
// 你也可以把any类型的数据赋值给其它变量都不会有问题
let name: string = 'dengxi'
name = any2
// 你也可以读取或者调用any类型的任意属性和方法
any5.change(); // 很明显js会报错,any5现在是一个数组类型,并没有change方法可以被调用。但es 不会检验出它的错误,因为any类型就相当于放弃了ts的规则校验
未知类型unknown
未知类型,适用于:起初不确定数据的具体类型,要后期才能确定
let a: unknown
//以下对a的赋值,均符合规范
a = 100
a = false
a = '你好'
感觉unknown和any很像,差别在哪儿呢?unknown类型只能对其任意赋值,却不能任意使用,这点与any不同,相对来说,它比any规范一点儿,安全一点儿。
let a: unknown = 'dengxi'
let b: boolean = false
b = a // ts会报错,不能将unknown类型赋值给boolean类型,但any类型可以赋值给任意类型。
a.change() // ts会报错,unknown类型不确定有change方法存在,所以unknown类型不能任意使用。
null 和 undefined
// undefined 类型 当你不知道某一个变量是否有值时,可以在联合类型中使用undefined
let undefined1: number | undefined = 1;
undefined1 = undefined;
let undefined2: number | undefined = undefined;
// undefined的值只能赋值为undefined
// let undefined3: undefined = null 是不对的
// null类型
let null1:null = null
// null只能赋值为null
// let null2:null = undefined
void类型
void类型,没有任何类型,一般用于方法没有返回值。
// a是一个函数,不接受任何参数,并自动返回undefined
let a: () => void = function () {}
function run(): void {
console.log(run);
}
// undefined 是void可以接受的一种空
function run1(): void {
console.log(run1);
return undefined
}
// 如果方法有返回值number
function run1(): number {
return 123
}
// 如果方法接收参数,返回number
let b: (c:string) => number = function (c) {
return Number(c)
}
返回void的函数 调用者不应该依赖返回值进行操作
function run1(): void {
console.log(run1);
return undefined
}
let result = run1()
// ts 不允许将void的值拿来做任何操作,即使你明白result应该是undefined
if(result === undefined) {
// 是不被ts允许的
}
但如果用undefined 替换void就不存在这种问题
function run1(): undefined {
console.log(run1);
return undefined // 即使不写,函数也是默认返回undefined
}
let result = run1()
if(result === undefined) {
// 是不被ts允许的
}
never类型
never表示 不能存在任何值,undefined也不行。
几乎不用never限制变量,没有意义。
一般用于函数中可能报错的逻辑,或者循环调用,永不结束的函数。
// never 类型 表示其它类型,常用于抛出异常,因为我们不知道抛出的异常是一个什么类型,never可以被any代替,不常用
let d: never = (() => {
throw new Error('未知的错误');
})();
function demo(): never {
throw new Error('程序异常')
}
object 类型
object(小写)的含义是:所有非原始类型,可存储:对象、函数、数组等,由于限制的范围比较宽泛,在实际开发中使用的相对较少。
// 以下代码,是将【非原始类型】赋给a,所以均符合要求
let a:object // a的值可以是任何【非原始类型】,包括:对象、函数、数组等
a = {}
a = {name:'张三'}
a = [1,3,5,7,9]
a = function(){}
a = new String('123') // 这是string的包装对象,所以也可以赋值给object类型
class Person {}
a = new Person()
// 以下代码,是将【原始类型】赋给a,有警告
a = 1 // 警告:不能将类型“number”分配给类型“object”
a = true // 警告:不能将类型“boolean”分配给类型“object”
a = '你好' // 警告:不能将类型“string”分配给类型“object”
a = null // 警告:不能将类型“null”分配给类型“object”
a = undefined // 警告:不能将类型“undefined”分配给类型“object”
Object 类型
官方描述:所有可以调用Object方法的类型。
· 简单记忆:除了undefined和null的任何值。
· 由于限制的范围实在太大了!所以实际开发中使用频率极低。
let b:Object //b的值必须是Object的实例对象(除去undefined和null的任何值)
// 以下代码,均无警告,因为给a赋的值,都是Object的实例对象
b = {}
b = {name:'张三'}
b = [1,3,5,7,9]
b = function(){}
b = new String('123')
class Person {}
b = new Person()
b = 1 // 1不是Object的实例对象,但其包装对象是Object的实例
b = true // truue不是Object的实例对象,但其包装对象是Object的实例
b = '你好' // “你好”不是Object的实例对象,但其包装对象是Object的实例
// 以下代码均有警告
b = null // 警告:不能将类型“null”分配给类型“Object”
b = undefined // 警告:不能将类型“undefined”分配给类型“Object”
type类型
// type 自定义类型,类似于定义一个变量,大驼峰式命名(行业规范,不遵守也不会报错),
// type 是为了方便快捷,当多个数据类型一致时,可以用一个变量的形式将这种类型保存下来,直接使用。
type TestType = [string, number, any];
const TestType1: TestType = ['dx', 18, '牛逼'];
const TestType2: TestType = ['yx', 18, 4564];
// type 自定义,你想怎么玩都可以,能满足复杂数据的类型设置,
type TypeTest = {
a: number;
b: string;
c: () => void;
};
const TypeTest1 = {
a: 18,
b: 'dx',
c: () => {
console.log(a);
},
};
// 联合 typea 可以是字符串 数字 布尔值
type Typea = string | number | boolean;
const Typea1: Typea = 1;
const Typea2: Typea = 'dx';
const Typea3: Typea = false;
交叉类型(Intersection Types)允许将多个类型合并为一个类型。合并后的类型将拥有所有被合并类型的成员。交叉类型通常用于对象类型。
//面积
type Area = {
height: number; //高
width: number; //宽
};
//地址
type Address = {
num: number; //楼号
cell: number; //单元号
room: string; //房间号
};
// 定义类型House,且House是Area和Address组成的交叉类型
type House = Area & Address;
const house: House = {
height: 180,
width: 75,
num: 6,
cell: 3,
room: '702'
};
一个特殊情况
先来观察如下两段代码:
代码段1(正常)
在函数定义时,限制函数返回值为void,那么函数的返回值就必须是空。
function demo():void{
// 返回undefined合法
return undefined
// 以下返回均不合法
return 100
return false
return null
return []
}
demo()
代码段2(特殊)
使用类型声明限制函数返回值为void时,TypeScript并不会严格要求函数返回空。
type LogFunc = () => void
const f1: LogFunc = () => {
return 100; // 允许返回非空值
};
const f2: LogFunc = () => 200; // 允许返回非空值
const f3: LogFunc = function () {
return 300; // 允许返回非空值
};
为什么会这样?
是为了确保如下代码成立,我们知道 Array.prototype.push 的返回值是一个数字,而Array.prototype.forEach方法期望其回调的返回类型是void。
const src = [1, 2, 3];
const dst = [0];
src.forEach((el) => dst.push(el));
官方文档的说明:Assignability of Functions
声明对象类型
1. 实际开发中,限制一般对象,通常使用以下形式
// 限制person1对象必须有name属性,age为可选属性
let person1: { name: string, age?: number }
// 含义同上,也能用分号做分隔
let person2: { name: string; age?: number }
// 含义同上,也能用换行做分隔
let person3: {
name: string
age?: number
}
// 如下赋值均可以
person1 = {name:'李四',age:18}
person2 = {name:'张三'}
person3 = {name:'王五'}
// 如下赋值不合法,因为person3的类型限制中,没有对gender属性的说明
person3 = {name:'王五',gender:'男'}
- 索引签名: 允许定义对象可以具有任意数量的属性,这些属性的键和类型是可变的,常用于:描述类型不确定的属性,(具有动态属性的对象)。
// 限制person对象必须有name属性,可选age属性但值必须是数字,同时可以有任意数量、任意类型的其他属性
let person: {
name: string
age?: number
[key: string]: any // 索引签名,完全可以不用key这个单词,换成其他的也可以
}
// 赋值合法
person = {
name:'张三',
age:18,
gender:'男'
}