初识TypeScript
TypeScript具有类型系统,是JavaScript的一个超集,扩展了JS的语法。因此,JS与TypeScript可以一起执行,TypeScript通过类型注解提供编译时的静态类型检查,仅编译特定的ts语法的代码段。
// 变量名:类型 = 值;
const a:number = 1;
TypeScript语法特性
- 类 Classes
- 模块 Modules
- 接口 Interfaces
- 编译时类型检查 Compile time type checking
- Arrow 函数
TypeScript安装
TypeScript有两种安装方法:
- NPM 安装:
npm install typescript -g
- MSI安装包安装(包下载地址)
安装完成,即可使用TypeScript编译器,名称叫tsc,可编译生成js文件,命令:tsc filename.ts
TypeScript学习
类型
TypeScript在变量后面添加:xx类型
就可以规定数据、方法的类型。
基础类型
- 字符串(
:string
) - 数字(
:number
) - 布尔(
:boolean
) - undefined(
:undefined
) - null(
:null
) - 空(
:void
) - 函数没有返回值或者返回值为空(undefined
)时 - 任意类型(
:any
) - 类型不确定时,就可以使用(Unknow
类型差不多,比any
安全) - 字面量:定义什么就只能使用什么(eg:
let animal:'dog'
则animal只能赋值为dog) - 枚举(
enum
)
// 可手动设置编号
enum Color {Red = 1, Green, Blue};
let c: Color = Color.Green;
复杂类型
- 数组array:(
:number[] / 数组泛型形式 :Array[number]
) - 元组tuple:长度固定的数组(
:[string, boolean]
) - 接口interface:能很方便的定义
Object
类型- 在
interface
属性中添加?
可以省略 readonly
不可改变的,定义完后就不能修改(和const
有点像:const
是针对变量,readonly
是针对属性)- 任意数量的其它属性:
[propName:String]: any
- 在
interface Infos {
name: string,
age: number,
readonly idCard: string, // 不可修改
male?: number, // 可省略
[propName:String]: any, // 其它任意属性
}
let customer:Infos = {
name: 'LeaT',
age: 18,
idCard: 'xxxxxx',
address: 'sss'
}
- 函数function
- 规定函数的输入类型和返回类型(传入多余参数会报错,可以为函数添加可选参数 即用
?
即可,可选参数后不可再添加必须的形参) - 形参后需要声明形参类型,函数名后需要声明返回值类型
- 规定函数的输入类型和返回类型(传入多余参数会报错,可以为函数添加可选参数 即用
function sumFun(num1:number, num2:number, num3?:number):number {
return num1 + num2 + (num3 || 0)
}
// 写法二
const sunFun = (num1:number, num2:number, num3?:number):number => {
return num1 + num2 + (num3 || 0)
}
定义函数类型变量
let mySum:(num1:number, num2:number, num3?:number) => number = sum
// 使用interface描述
interface sumObject {
(num1:number, num2:number, num3?:number): number
}
let mySum:sumObject
// 使用时 可不指定类型
mySum = funtion(num1, num2, num3?) {
return num1 + num2 + num3 || 0
}
-
联合类型union types(避免
any
类型的使用)- 几种类型使用
|
分隔 - 在没有赋值之前,仅可访问共同的方法、属性
- 几种类型使用
-
对象Object(简约处理
interface
的声明)
let obj:{width:number, height:number}
obj = {
width: 12,
height: 24
}
类型断言(type inference)
使用联合类型的时候,由于未赋值之前仅可使用公有的方法和属性。
但是在某些时候,你清楚地知道一个实体具有比它现有类型更确切的类型,通过类型断言方式可以告诉编译器,“相信我,我知道自己在干什么”。类型断言好比类型转换,但是不进行特殊的数据检查和解构,只在编译阶段起作用。
写法
- 尖括号:
<string>param
as
写法:param as string
(使用JSX时,仅as
写法有效)
类型守卫
使用联合类型的时候,需要针对某些类型做特殊返回或者处理,这个时候就需要用到typeof
、instanceof
等类型判断方法。
function getLen(params: number | string):number {
if(typeof params === 'string') return params.length;
return params.toString().length
}
泛型(T
)
泛型就像一个占位符一个变量,在使用的时候可以将定义好的类型像参数一样传入,原封不动的输出。
function getValue<T,U>(params:[T,U]):[T,U] {
return params
}
在使用的时候,编译器就会自己判断并修改传入的类型。
在此,我们可以使用interface
来约束泛型。
eg:约束传入的参数必须有length
属性
interface needLen {
length: number
}
function getLen<T extends needLen>(params:T):number {
return params.length
}
// 使用
getLen('str') // 3
getLen([]) // 0
getLen(124) // error
类中使用泛型
class Animal<T> {
singing(name: T) {
console.log(name)
}
}
let kit = new Animal<string>()
kit.singing('lalala') // lalala
kit.singing(2342) // error
接口中使用泛型
class getValue<T, U> {
key: T,
value: U
}
let test1:getValue<string, number> = {key: 'test1', value: 1}
let test1:getValue<number, number> = {key: 2, value: 2}
数组中使用泛型
let array1:Array<number> = [1,2,3,4,5]
let array2:Array<string> = ['1','2','3']
类型别名(type
)
type numStrType = number | string
let num:numberType = 243
交叉类型(&
)
interface valueKey {
key: string
}
test valType = valueKey & {value: string}
let testValue:valueType = {kay: 'test', value: 'val'}
类 class
每个类都有一个constructor
属性,new
时会执行该构造函数并初始化它。
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
参数修饰符
public
:公共privated
:私有的,只能在本类访问protected
:受保护的,只能在本类和子类中访问
静态属性(static
)
静态属性是用过类访问的,是每个实例共有的,可以直接调用。
只读属性(readonly
)
即只能读取,不能修改。如果存在 static
修饰符,写在其后
class MyClass {
static readonly species:string = 'haha'
}
抽象类(abstract
)
TypeScript新增的抽象类:使创建的类只能被继承,不能被实例化(即不能new
)
- 在
class
前面 添加abstract
修饰符; - 在抽象类中写抽象方法,抽象类没有方法体
abstract class Animal {
constructor(name: string) {},
abstract singing():void
}
class Cat extends Animal {
constructor(name:string) {
super(name)
}
singing() {
console.log('miao~')
}
}
继承 (extends
)
类最常见使用就是类的继承使用。使用extends
关键字来基于基类创建子类,使其子类均可以访问基类的属性和方法。
constructor
的派生类必须调用super()
,用于执行基类的构造方法;- 类中的成员,默认都是公有的,即
public
声明; private
修饰成员变量后,则不能在声明它的类的外部访问;protected
修饰变量后,派生类中可以访问(构造函数也可以被标记为protected
,表示这个类不能在包含它的类外被实例化);
class Animal {
name:string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}
class Horse extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 45) {
console.log("Galloping...");
super.move(distanceInMeters);
}
}
let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);
输出:
Slithering...
Sammy the Python moved 5m.
Galloping...
Tommy the Palomino moved 34m.
class Person {
protected name: string;
protected constructor(theName: string) { this.name = theName; }
}
// Employee can extend Person
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // Error: The 'Person' constructor is protected
参数属性
参数属性可以方便地让我们在一个地方定义并初始化一个成员。 下面的例子是对之前Animal
类的修改版,使用了参数属性:
class Animal {
constructor(private name: string) { }
move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
// 等同于
name:string,
constructor (theName: string) {
this.name = theName;
}
声明和赋值合并至一处:参数属性通过给构造函数参数添加一个访问限定符来声明,和在声明变量之前添加修饰符作用一致。
接口 (interface
)
接口的存在,是为了解决一个类只能继承另一个类,而不能实现多继承的困境。
通过实现一个接口,将某个共有的功能抽离出来,使得多个类去实现该接口即可。
我们通过使用关键字implements
来实现接口。
interface getColor {
generateCol():void
}
interface getSize {
generateSize():void
}
// 通过,连接多个接口 实现多个接口功能
class getCircleItem implements getColor,getSize {
generateCol(num) {
return num * 2
}
generateSize() {
console.log('size')
}
}
接口可以继承,通过继承,可以细化和合并实现不同功能项
interface getColor {
generateCol():void
}
interface getSize extends getColor {
generateSize():void
}
// 通过,连接多个接口 实现多个接口功能
class getCircleItem implements getSize {
generateCol(num) {
return num * 2
}
generateSize() {
console.log('size')
}
}
TypeScript内置的类型方法和工具类型
工具类型
Partial<T>
:将T
类型的所有属性变为可选;Required<T>
:将T
类型的所有属性变成必须;Readonly<T>
:将T
类型的所有属性变成只读;Record<T,K>
:创建一个具有指定键类型K
和值类型T
的新对象类型Pick<T,K>
:从类型T
中选择指定属性K
形成新的类型Omit<T,K>
:从类型T
中排除指定属性K
形成新的类型Exclude<T,U>
:从类型T
中排除可以赋值给类型U
的类型Extract<T,U>
:从类型T
中提取可以赋值给类型U
的类型NonNullable<T>
:从类型T
中排除null
和undefined
类型ReturnType<T>
:获取函数类型T
的返回类型Parameters<T>
:获取函数类型T
的参数类型组成的元组类型
条件判定类型
条件类型是一种灵活的类型构造方式,它允许根据类型关系进行条件判断生成不同的类型。
条件类型
- 条件类型基于输入的类型关系来确定最终的类型,通常结合
extends
关键词来使用。
type TypeName<T> =
T extends string ? "string" :
T extends number ? "number" :
T extends boolean ? "boolean" :
"other";
type A = TypeName<string>; // A 的类型为 "string"
type B = TypeName<number>; // B 的类型为 "number"
type C = TypeName<boolean>; // C 的类型为 "boolean"
type D = TypeName<object>; // D 的类型为 "other"
type E = TypeName<string | number>; // E 的类型为 "string" | "number"
- 条件类型中使用
infer
关键字,用于在条件类型内部声明一个类型变量,并从中提取或推断出一个类型,它允许我们在泛型条件类型中推断出待推断类型的部分。 - 条件类型配合泛型使用
分布式条件类型
分布式条件类型在联合类型上进行推断和分发,并返回联合类型中每个成员的条件类型。
type ToArray<T> = T extends any ? T[] : never;
type StrArray = ToArray<string>; // StrArray 的类型为 string[]
type NumArray = ToArray<number>; // NumArray 的类型为 number[]
type UnionArray = ToArray<string | number>; // UnionArray 的类型为 (string | number)[]
映射类型
TypeScript中的映射类型,允许通过已有类型来创建新类型,通常是通过映射现有类型的属性、方法或者创建新的属性来实现。
创建的映射类型是利用keyof
关键字配合索引类型来生成新的类型。
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface User {
name: string;
age: number;
}
type PartialUser = Partial<User>;
// PartialUser 类型为 { name?: string; age?: number; }
模板文字类型
模板文字类型允许在类型系统中对字符串文本进行操作和替换。使用${}
语法来动态的创建字符串字面量类型。
类型推断关键字
typeof
:类型查询操作符,用户获取变量或表达式的类型,返回该值的类型字符串表示instanceof
:用于检查对象是否是特定类的实例,返回布尔值检查结果in
:检查对象是否具有特定属性;- type guards:类型守卫是自定义的函数或条件语句,用于在代码块内缩小变量的类型范围。它们可以是
typeof
、instanceof
或者其它自定义条件的组合 as
:用于类型断言,允许将一个变量断言为特定的类型。