TypeScript基础
TypeScript 是由微软开发的一种开源编程语言。它是 JavaScript 的一个超集,意味着它包含了所有 JavaScript 的功能,同时增加了一些额外的特性。主要特点包括:
静态类型检查:TypeScript 允许在编译时进行类型检查,这有助于捕捉潜在的错误。通过明确指定变量和函数的类型,可以减少运行时错误。
面向对象编程特性:TypeScript 支持类(classes)、接口(interfaces)、继承(inheritance)等面向对象编程的特性,使得代码结构更清晰,更易于维护。
兼容性:TypeScript 可以编译成纯 JavaScript 代码,并且与所有现有的 JavaScript 库和框架兼容。这意味着你可以在任何可以运行 JavaScript 的环境中使用 TypeScript,包括浏览器和Node.js。
工具支持:由于其静态类型特性,TypeScript 提供了更好的代码编辑器支持,如智能感知(IntelliSense)、代码补全和重构等。这些工具可以极大提高开发效率。
开发者社区:TypeScript 有一个庞大而活跃的开发者社区,提供了丰富的资源、教程和库,帮助开发者更快上手并解决问题。
TypeScript 的目标是通过引入类型系统和其他现代编程语言的特性,提升 JavaScript 的开发体验和代码质量。
type User = {
name: string;
age: number;
};
function isAdult(user: User): boolean {
return user.age >= 18;
}
const justine: User = {
name: 'Justine',
age: 23,
};
const isJustineAnAdult: boolean = isAdult(justine);安装
TypeScript是npm模块,可以通过npm安装,或在node项目中安装为项目依赖。
通过以下命令可以全局安装TypeScript。
npm install -g TypeScript查看TypeScript版本
npx tsc -v查看TypeScript帮助
npx tsc -h
npx tsc --all将TypeScript脚本编译成JavaScript脚本,将在app.ts的目录下生成一个app.js的文件。
npx tsc app.ts基础知识
后置类型注释
TypeScript使用后置类型注释,参数或属性的类型使用:类型注释。
变量的类型注释
使用 const、var 或 let 声明变量时,可以选择添加类型注释以显式指定变量的类型:
let myName:string="Evan";
//等价于
let myName="Evan";在大多数情况下,变量类型注释不是必须的。TypeScript 会尽可能自动推断代码中的类型。
函数的类型注释
TypeScript对Function提供两个方面的静态类型检查:
- 参数类型注释
- 返回类型注释
function greet(person: string, date: Date):string {
console.log(`Hello ${person}, today is ${date.toDateString()}!`);
return `Hello ${person}, today is ${date.toDateString()}!`;
}类型注释
基础类型
字面量
小写类型仅表示字面量
- string:字符串
let a:string="123456";- number:数值类型
let n:number=12345;- boolean:布尔值。
let b:boolean=true;包装对象和字面量
大写类型同时包含对象和字面量
- String:字符串
let a:String="123456";
let b:String=new String('123456');- Number:数值类型
let n:Number=12345;
let m:Number=new Number(1234);- Boolean:布尔值。
let b:Boolean=true;
let c:Boolean=new Boolean(true);文本类型
当使用const定义一个文本类型或数值类型的常量时,TypeScript实际上会使用值本身作为常量的类型。
const constantString = "Hello World";
//相当于
const constantString:"Hello World";
const constantNumber=1|2|3;
const constantNumber:1|2|3;Array数组类型
string[]
//等价于
Array<string>ReadonlyArray只读数组类型
ReadonlyArray 是一种特殊类型,用于描述不应更改的数组。
function doStuff(values: ReadonlyArray<string>) {
// We can read from 'values'...
const copy = values.slice();
console.log(`The first value is ${values[0]}`);
// ...but we can't mutate 'values'.
values.push("hello!");
//Property 'push' does not exist on type 'readonly string[]'.
}
//或简写
function doStuff(values: readonly string[]) {
}元组类型Tuple Types
元组类型是另一种 Array 类型,使用[]表示,它确切地知道它包含多少个元素,以及它在特定位置包含哪些类型。
type StringNumberPair = [string, number];
function doSomething(pair: [string, number]) {
const a = pair[0];
//const a is string
const b = pair[1];
//const b is number
}
doSomething(["hello", 42]);元组也可以添加可选属性
type Either2dOr3d = [number, number, number?];元组也可以具有rest元素,rest元素必须是解构的数组/元组类型,rest元素的数量可以是任意的。
type StringNumberBooleans = [string, number, ...boolean[]];
type StringBooleansNumber = [string, ...boolean[], number];
type BooleansStringNumber = [...boolean[], string, number];元组也支持readonly属性
function doSomething(pair: readonly [string, number]) {
// ...
}any任意类型
当一个值是 any 类型时,你可以访问它的任何属性(返回的也是 any 类型),像函数一样调用它,将其分配给任何类型的值或将任何类型的值分配给它,或者做任何其他语法上合法的事情。
let obj: any = { x: 0 };
//不会触发编译警告
obj.foo();unknow类型
unknow类型表示不清楚一个变量的类型,它类似于any,但是比any严格。unknow类型的变量,不能赋值给其他类型的变量,不能调用unknow类型的方法和属性,运算也是有限的,只能进行比较运算、取反运算、typeof、instanceof运算等。unknow一般用于函数的入参类型,在经过类型缩小后,可以像目标类型一样正常使用。
function print(str:unknow){
if(typeof str === 'string'){
console.log(str);
}
}never类型
never类型表示空类型,没有类型。never类型的变量不能对其进行赋值,但它可以赋值给任何类型。在数学上,空集是任务集合的子集。TypeScript遵循了这个原则。因此never可以赋值给任务类型,而不能对其进行赋值。
never的主要用途用在函数的返回值上,当一个函数不返回任何值时,那这个函数的运行结果则为never类型的。
function f():never {
throw new Error('Error');
}
let v1:number = f(); // 不报错
let v2:string = f(); // 不报错
let v3:boolean = f(); // 不报错object对象类型
可以直接给参数注释一个对象类型
//使用?号表示对象的可选属性
function printName(obj: { first: string; last?: string }) {
// ...
}
// Both OK
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });union联合类型
使用|号表示联合类型。表示一个变量可以是多个类型中的一种。联合类型包含的属性是各个类型的属性的交集。使用需要注意,若使用了非交集内的属性,需要利用分支区分开。
function printId(id: number | string) {
if (typeof id === "string") {
// In this branch, id is of type 'string'
console.log(id.toUpperCase());
} else {
// Here, id is of type 'number'
console.log(id);
}
}
// Return type is inferred as number[] | string
function getFirstThree(x: number[] | string) {
return x.slice(0, 3);
}generics泛型
使用<>定义一个泛型。泛型可以用在数组上,表示数组包含元素的类型。或用在函数签名上,表示函数参数的类型。
type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0];
}
let numbers:number[]=[1,2,3];
let n:number=firstElement<number>(numbers);
interface Box<Type>{
content:Type;
}类型断言
类型断言是指对参数或函数返回的结果指定其类型。有时候我们调用一个函数,函数返回的结果的类型会是抽象类型(比如Person),而我们需要获得一个更具体的类型(比如Man),则需要用到类型断言。
在TypeScript中,使用关键词as或尖括号<>实现类型断言。
const oneMan=getPerson() as Man;
//等价于
const oneMan=<Man>getPerson();使用类型断言时,TypeScript 只允许类型断言转换为更具体或不太具体的类型版本。意思是转换的类型要与原类型有关联关系。不允许将一个string类型变量断言为number类型。如果有这场场景发生,使用两个断言,首先是 any(或 unknown,我们将在后面介绍),然后是所需的类型:
const a=expr as any as T;非空断言运算符(!)
TypeScript 还具有一种特殊的语法,用于从类型中删除 null 和 undefined,而无需执行任何显式检查。在任何表达式之后写入!实际上是一个类型断言,该值不是 null 或 undefined:
function liveDangerously(x?: number | null) {
// No error
console.log(x!.toFixed());
}narrowing缩小类型范围
narrowing是编写TypeScript过程中需要注意事项。当面对一个拥有多个可能的类型的变量时,TypeScript的类型推断可能无法直接工作,在编译时会提出告警。缩小变量的类型范围是处理这种场景的方法。常用的缩小变量类型的方法用:
- 使用if-else条件分支语句搭配typeof关键词,缩小变量类型范围。
- 使用
!去排除为null或者undefined的变量。 - 对多个变量使用switch语句或相等性检查(如
===、!==、==和!=)来缩小类型范围。 - 使用in关键词确定对象或其原型链是否具有指定名称的属性。
- 使用instance关键词检查一个值是否是另一个值的 “实例”。
- 使用类型谓词。
parameterName is Type。
可选参数
在TypeScript使用?将函数参数设置为可选的。
function f(x?: number) {
// ...
}
f(); // OK
f(10); // OKTypeScript中的函数
函数重载
javascript不支持函数重载。在 Java 中,你可以定义多个具有相同名称但不同参数的函数,而 JavaScript 只能有一个函数定义。
在JavaScript中实现函数重载,可以在一个函数内部通过检查 arguments.length 或使用参数默认值和展开运算符 ... 来实现类似的功能。
function example() {
if (arguments.length === 1) {
console.log("One argument: ", arguments[0]);
} else if (arguments.length === 2) {
console.log("Two arguments: ", arguments[0], arguments[1]);
} else {
console.log("No or more than two arguments.");
}
}TypeScript支持函数重载。可以通过定义多个函数签名来实现这一点,然后实现一个具体的函数来处理这些重载。
//函数重载签名
function example(input: string): void;
function example(input: number): void;
function example(input: boolean): void;
//函数实现签名
function example(input: any): void {
if (typeof input === "string") {
console.log("String input: ", input);
} else if (typeof input === "number") {
console.log("Number input: ", input);
} else if (typeof input === "boolean") {
console.log("Boolean input: ", input);
} else {
console.log("Unsupported input type.");
}
}函数中的几个类型
- void:当函数没有return语句时,或没有从return中返回任何值时,函数的返回类型为void。
- object:这个特殊类型object引用任何值,不包括非基元值(string、number、bigint、boolean、symbol、null 或 undefined)。它会Javascript的Object(O大写)类型不同。
- unknow:unknown类型表示任何值。这类似于any类型,但更安全,因为对未知值执行任何操作都是不合法的,即不能对它进行任务操作。
- never:never类型表示从未观察到的值。在返回类型中,这意味着函数引发异常或终止程序的执行。
- Function:全局类型 Function 描述了 JavaScript 中所有函数值上存在的属性,如 bind、call、apply 和其他属性。它还具有始终可以调用 Function 类型的值的特殊属性;这些调用返回 any。
函数的多个可选参数
使用...定义接受无限数量的参数的函数,它必须出现在所有其他参数之后。
function multiply(n: number, ...m: number[]) {
return m.map((x) => n * x);
}在 TypeScript 中,这些参数的类型注释隐式是 any[] 而不是 any,并且给出的任何类型注释都必须是 Array<T> 或 T[] 的形式,或者是元组类型。
TypeScript中的类型
声明类型
1. 使用type定义复杂类型
可以通过关键词type定义复杂的类型。
type Point = {
x: number;
y: number;
};
type ID = number | string;
type LockStates = "locked" | "unlocked"; //文本类型
type PositiveOddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;2. 使用interface定义复杂类型
可以通过关键词interface定义复杂的类型。
interface User {
name: string;
id: number;
}类型属性的修饰符
对象类型中的每个属性都可以指定以下几个可选属性修饰符:
- 属性的类型
- 属性是否可选。在属性名后加
?,表示属性是一个可选属性。
interface point{
xPos?: numner;
ypos?: number;
}- 属性是否只读。在属性名前加readonle,表示属性是一个只读属性。TypeScript在编译时会对其进行检查。属性的引用不能改变,属性的引用内的值可以改变。
interface SomeType {
readonly prop: string;
}type与interface的区别
类型别名和接口非常相似,在许多情况下,您可以在它们之间自由选择。接口的几乎所有功能都可以在类型中使用,关键区别在于类型不能重新打开以添加新属性,而接口总是可扩展的。
1. 拓展接口
interface可以通过extends拓展属性,type通过并集拓展属性。
//interface
interface Animal {
name: string;
}
interface Bear extends Animal {
honey: boolean;
}
//type
type Animal = {
name: string;
}
type Bear = Animal & {
honey: boolean;
}2. 添加字段
interface可以通过重复定义直接添加新字段,type不能重复定义。
//interface
interface Window {
title: string;
}
interface Window {
ts: TypeScriptAPI;
}
//type
type Window = {
title: string;
}
// Error: Duplicate identifier 'Window'.
type Window = {
ts: TypeScriptAPI;
}Index Signatures 索引签名
类型中可以添加一个索引签名,当我们不清楚属性的具体名称,但知道类大致结构时,可以通过索引签名访问属性。
interface StringArray {
[index: number]: string;
}
const myStringArray:StringArray=getStringArray();
myStringArray[0]="index-0-value";需要注意的时,索引签名的类型必须与类中的属性类型匹配,否则TypeScript将会抛出编译警告。
超额属性检查
超额属性检查,是指向一个函数传递一个对象时,传递的对象的属性超过了其声明时的范围,TypeScript会对这种场景进行警告。
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
return {
color: config.color || "red",
area: config.width ? config.width * config.width : 20,
};
}
let mySquare = createSquare({ colour: "red", width: 100 });比如上面这段代码,SquareConfig中并不存在colour属性,而是color属性。这段代码虽然在JavaScript中没有问题,但是TypeScript提供了更严格的检查以避免这种情况。
交集类型Intersection Types
interface除了允许我们通过extends拓展类型来创建新类型,TypeScript还提供了交集类型的方式,拓展现在类型。
交集类型通过&符定义。
interface A{
name:string;
}
interface B{
age:number;
}
interface person=A&B;从类型创建类型
通过组合各种类型运算符,我们可以以简洁、可维护的方式表达复杂的操作和值。这些方法包括:
- 泛型:带参数的类型
interface A<T>{
arg:T;
}- keyof类型运算符:keyof运算符在TypeScript中主要用于获取对象类型的键(key),因此它只能作用于对象类型(type 或 interface)
type Person{
name:string;
age:number;
}
type PersonKey= keyof Persion;
// PersonKey的类型与"name"|"age"相同- typeof类型运算符:typeof运算符用于引用变量或属性的类型。
function f() {
return { x: 10, y: 3 };
}
//ReturnType<T> 是 TypeScript 用来获取函数返回类型的工具类型
type P = ReturnType<typeof f>;
/*
type P = {
x: number;
y: number;
}
*/- 索引访问类型:使用索引访问类型
Type['a']语法访问另一个类型上的特定属性。
type Person{
name:string;
age:number;
}
type Age=Person['age'];
// type Age = number;- 条件类型:类似于类型系统中 if 语句的类型,一般用法是使用三元运算结合泛型定义新的类型。
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
type Example1 = Dog extends Animal ? number : string;
//type Example1 = number
type Example2 = RegExp extends Animal ? number : string;
//type Example2 = string- 映射类型:通过映射现有类型中的每个属性来创建类型。
type OnlyBoolsAndHorses = {
[key: string]: boolean | Horse;
};
const conforms: OnlyBoolsAndHorses = {
del: true,
rodney: false,
};
type CreateMutable<Type> = {
-readonly [Property in keyof Type] -?: Type[Property];
};
type MaybeUser = {
readonly id: string;
name?: string;
age?: number;
};
type MaybeUserKey = CreateMutable<MaybeUser>;
/*
type MaybeUserKey = {
id: string;
name: string;
age: number;
}
*/- 模板文字类型:通过模板文字字符串更改属性的映射类型。类型于JavaScript中的模板字符串。
type World = "world";
type Greeting = `hello ${World}`;
//type Greeting = "hello world"
type Event = "click" | "focus" | "hover";
type EventHandler = {
[K in Event as `on${Capitalize<K>}Event`]: () => void;
};
// EventHandler 类型等价于:
// {
// onClickEvent: () => void;
// onFocusEvent: () => void;
// onHoverEvent: () => void;
// }TypeScript中的类
定义类
通过class以面向对象编程的方式组织代码。
class Student {
fullName: string;
constructor(
public firstName: string,
public middleInitial: string,
public lastName: string
) {
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}在构造函数中使用public、private等修饰符修饰参数是一种简写,它允许我们自动创建具有该名称的属性。
类的属性
类中的每个属性都可以指定以下几个可选属性修饰符:
- 属性的类型
- 属性是否可选。在属性名后加
?,表示属性是一个可选属性。
class point{
xPos?: numner;
ypos?: number;
}- 属性是否只读。在属性名前加readonle,表示属性是一个只读属性。TypeScript在编译时会对其进行检查。属性的引用不能改变,属性的引用内的值可以改变。
clas SomeType {
readonly prop: string;
}类的方法
就将其他面向对象语言如java一样,定义类的方法,在TypeScript可以给方法的参数添加类型注释,给方法的返回添加类型注释。
class Point {
x = 10;
y = 10;
scale(n: number): void {
this.x *= n;
this.y *= n;
}
}要引用类的属性时,使用this指针。
类属性的访问器
TypeScript中,可以通过get、set关键词定义类属性的访问器。
class C {
_length = 0;
get length() {
return this._length;
}
set length(value) {
this._length = value;
}
}在 TypeScript 中,给类的属性名称加下划线(如 _length)并没有特殊的语法或内置功能上的作用,但它是一种命名约定。
- 区分属性和getter/setter方法。
- 表示私有性或不应直接访问。
- 历史遗留习惯: 在早期没有严格私有成员的 JavaScript 编程中,下划线前缀是一种常见的约定方式,开发者用它来表示这个属性不应该直接使用。
更推荐的做法是,给_length属性添加private修饰符,使其真正变成私有的,外部代码无法直接访问它。
class C {
private _length = 0;
get length() {
return this._length;
}
set length(value) {
this._length = value;
}
}TypeScript 对于访问器有一些特殊的推理规则:
- 如果get存在但没有set ,则该属性自动readonly。
- 如果没有指定setter参数的类型,则从getter的返回类型推断。
类的继承
使用关键字extends,实现类的继承。
class Base {
k = 4;
}
class Derived extends Base {
constructor() {
// Prints a wrong value in ES5; throws exception in ES6
console.log(this.k);
//此处应该使用super.k指向父类的k属性,而不是this指针
super();
}
}在子类的构造函数中访问父类的属性时,应使用super指针。
类实现接口
使用关键字implements实现接口。
interface Pingable {
ping(): void;
}
interface Pongable {
pong(): void;
}
class Sonar implements Pingable,Pongable {
ping() {
console.log("ping!");
}
pong() {
console.log("pong!");
}
}初始化顺序
- 初始化基类字段
- 执行基类构造函数
- 初始化派生类集类字段
- 执行派生类构造函数
class Base {
name = "base"; //1
constructor() { //2
console.log("My name is " + this.name);
}
}
class Derived extends Base {
name = "derived";//3
//4 执行Deriver的默认构造方法
}
// Prints "base", not "derived"
const d = new Derived();类成员可见性
类成员可见性关键字用于控制某些方法或属性是否对类外部的代码可见,包括:
- public:类成员的默认可见性是public 。 public成员可以在任何地方访问。
- protected:protected成员仅对声明它们的类和子类可见。
- private:类似于protected ,但不允许从子类访问该成员。
需要注意的是,类成员可见性仅在TypeScript类型检查期间执行,在javascript运行时时可以访问private、protected成员的。
在ES6之后,JavaScript类中可以使用#来定义私有字段。私有字段只能在类的内部访问,外部无法直接访问或修改。这是用来封装类内部实现细节的重要机制。
类静态成员
类可以有static成员。这些成员不与该类的特定实例相关联。可以通过类构造函数对象本身访问它们:
class MyClass{
static x=0;
static printX(){
console.log(MyClass.x);
}
}
console.log(MyClass.x);
MyClass.printX();name 、 length和call等函数属性不能定义为static成员。
定义泛型类
类与类型很相似,也可以定义泛型类。泛型类的类型在new实例时确定。
class Box<Type> {
contents: Type;
constructor(value: Type) {
this.contents = value;
}
}
const b = new Box("hello!");
//const b: Box<string>注意事项:泛型类的static成员永远不能引用该类的类型参数。
抽象类与抽象方法
TypeScript中使用abstract定义抽象类和抽象方法。
abstract class Base {
abstract getName(): string;
printName() {
console.log("Hello, " + this.getName());
}
}
class Derived extends Base {
getName() {
return "world";
}
}
const d = new Derived();
d.printName();抽象类不能直接实例化。需要创建一个派生类继承它,并实现其抽象成员。
类之间的关系
在大多数情况下,TypeScript 中的类会在结构上与其他类型进行比较。
如果两个类的结构相同,这两个类则可以互相替代。
class Point1 {
x = 0;
y = 0;
}
class Point2 {
x = 0;
y = 0;
}
// OK
const p: Point1 = new Point2();同样,即使两个类没有显示的继承关系,但是类之间存在子类型关系。
class Person {
name: string;
age: number;
}
class Employee {
name: string;
age: number;
salary: number;
}
// OK
const p: Person = new Employee();TypeScript中的模块
ES式的导入接口和类型
TypeScript的导入导出语法,支持导出接口和类型。语法与JavaScript的导入导出类似。
// @filename: animal.ts
export type Cat = { breed: string; yearOfBirth: number };
export interface Dog {
breeds: string[];
yearOfBirth: number;
}
// @filename: app.ts
import { Cat, Dog } from "./animal.js";
type Animals = Cat | Dog;TypeScript对Import语法进行了拓展,增加了两种导入方式
import type:仅导入类型。- inline type imports:内联类型导入。
仅导入类型
// @filename: animal.ts
export const createCatName = () => "fluffy";
// @filename: app.ts
import type { createCatName } from "./animal.js";
// (alias)const createCatName:()=>string
// import createCatName
const name = createCatName();
// 'createCatName' 不能被用作一个值,因为它是以类型的形式导入的。内联类型导入
内联类型导入是指在导入时添加type修饰符,表明导入的是类型。
// @filename: app.ts
import { createCatName, type Cat, type Dog } from "./animal.js";
export type Animals = Cat | Dog;
const name = createCatName();CommonJS式的导入导出
导出时,通过设置变量module的exports属性导出。
function absolute(num: number) {
if (num < 0) return num * -1;
return num;
}
module.exports = {
pi: 3.14,
squareTwo: 1.41,
phi: 1.61,
absolute,
};然后通过require语法导入
const maths = require("./maths");
maths.pi;
//或通过结构语法导入↓
const { squareTwo } = require("./maths");
squareTwo;工具类型
Awaited<Type>:这种类型旨在对async函数中的await或Promise上的.then()方法等操作进行建模。具体来说,它们递归地解开Promise的方式。Partial<Type>:构造一个类型,并将Type的所有属性设置为可选。该类型将返回一个表示给定类型的所有子集的类型。Required<Type>:构造一个类型,其中包含Type中设置为必需的所有属性。Readonly<Type>:构造一个类型,并将Type的所有属性设置为readonly ,这意味着构造类型的属性不能重新分配。Record<Keys, Type>:构造一个对象类型,其属性键为Keys ,其属性值为Type 。该实用程序可用于将一种类型的属性映射到另一种类型。Pick<Type, Keys>:通过从Type中选取属性Keys (字符串文字或字符串文字的并集)集来构造类型。Omit<Type, Keys>:通过从Type中选取所有属性,然后删除Keys (字符串文字或字符串文字的并集)来构造类型。与Pick相反。Exclude<UnionType, ExcludedMembers>:通过从UnionType中排除所有可分配给ExcludedMembers的联合成员来构造类型。Extract<Type, Union>:通过从Type中提取可分配给Union所有联合成员来构造类型。NonNullable<Type>:通过从Type中排除null和undefined来构造类型。NonNullable<Type>:通过从Type中排除null和undefined来构造类型。Parameters<Type>:根据函数类型Type的参数中使用的类型构造元组类型。ConstructorParameters<Type>:从构造函数类型的类型构造元组或数组类型。它生成一个包含所有参数类型的元组类型(如果Type不是函数,则never该类型)。ReturnType<Type>:构造一个由函数Type的返回类型组成的类型。InstanceType<Type>:构造一个由Type中构造函数的实例类型组成的类型。NoInfer<Type>:阻止对所包含类型的推断。除了阻止推理之外,NoInfer<Type>与Type相同。ThisParameterType<Type>:提取函数类型的this参数的类型,如果函数类型没有this参数,则为未知。OmitThisParameter<Type>:从Type中删除this参数。如果Type没有显式声明this参数,则结果只是Type 。否则,将从Type创建一个没有this参数的新函数类型。泛型被删除,只有最后一个重载签名被传播到新的函数类型中。ThisType<Type>:此实用程序不返回转换后的类型。相反,它充当上下文this类型的标记。请注意,必须启用noImplicitThis标志才能使用此实用程序。- 固有字符串操作类型:
Uppercase<StringType>:将 StringType 中的所有字母转换为大写。Lowercase<StringType>:将 StringType 中的所有字母转换为小写。Capitalize<StringType>:将 StringType 的首字母转换为大写,其他字母保持不变。Uncapitalize<StringType>:将 StringType 的首字母转换为小写,其他字母保持不变。
装饰器
TypeScript 的装饰器(Decorator)是一种特殊的语法,类似于java的注解+反射功能,用于修改类、方法、属性或参数的行为。它是一种元编程的特性,允许你通过注解的方式为代码添加额外的逻辑,通常用于简化代码、提高可读性、或者实现一些重复功能的抽象。装饰器广泛用于框架中,例如 Angular 里大量使用的装饰器,用于标记组件、服务等。
装饰器类型
1. 类装饰器
作用于类上,能够修改类的行为。它接受构造函数作为参数,并可以返回一个新的构造函数。
2.方法装饰器
作于类方法上,可以用来修改方法的行为。例如,记录方法调用时间、控制方法执行权限等。它接受3个参数:
- target:被装饰的对象。
- propertyKeys:被装饰的属性的名称。
- descriptor:属性描述符,可以用来修改方法的可写性、可枚举性等。
3. 属性装饰器
作用于类的属性上,常用于数据的验证或数据绑定。它接收两个参数:
- target: 被装饰的类。
- propertyKey: 被装饰的属性名称。
4. 参数装饰器
用于装饰方法的参数,可以在参数传递时进行拦截、验证等操作。它接收三个参数:
- target: 被装饰的对象。
- propertyKey: 方法名称。
- parameterIndex: 参数在方法参数列表中的索引。
应用场景
- 依赖注入:装饰器可以用来标记依赖项,从而实现依赖注入机制(如 Angular)。
- 权限控制:在方法装饰器中添加权限控制逻辑。
- 数据验证:属性装饰器可以用来自动验证类的属性。
- 日志记录:方法装饰器可以用来记录方法执行时间、输入输出等日志。
枚举Enums
枚举允许开发人员定义一组命名常量。使用枚举可以更轻松地记录意图,或创建一组不同的案例。 TypeScript 提供基于数字和字符串的枚举。
数字枚举
enum Direction {
Up = 1,
Down,
Left,
Right,
}枚举的所有成员都会自动递增,即使不显示声明,即当Up=1时,Down=2,Left=3,Rigth=4。
字符串枚举
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}Mixins混入
在 TypeScript 中,mixins 是一种将多个类的行为组合在一起的技术。它允许你通过组合多个类的功能来构建一个新的类,而不是依赖单一的继承链。这对于代码复用和模块化非常有帮助,特别是在需要多个类之间共享相似功能的情况下。
namespace命名空间
在Typescript中,命名空间也称为内部模块,主要用于在模块内部进一步将代码按模块或逻辑单元进行分组。
namespace用export向外提供属性或接口,而隐藏内部实现的代码。
namespace MyNamespace {
export class MyClass {
sayHello() {
console.log('Hello from MyNamespace!');
}
}
export function myFunction() {
console.log('This is a function inside MyNamespace.');
}
}
const myClassInstance = new MyNamespace.MyClass();
myClassInstance.sayHello();
MyNamespace.myFunction();类型声明文件.d.ts
在 TypeScript 中,.d.ts文件是声明文件,它的作用是为现有的JavaScript代码提供类型说明。.d.ts文件不包含实际的实现代码,它只提供类型定义和接口,用于帮助TypeScript编译器在编译时理解那些没有明确类型的库或模块。这种文件特别有用的场景包括:
- 与JavaScript库交互:如果你在TypeScript项目中使用了纯JavaScript库(比如jQuery、Lodash等),这些库没有类型定义,TypeScript编译器就无法理解它们的类型。通过引入
.d.ts文件,你可以让编译器知道这些库的类型,从而获得完整的类型检查和代码提示。 - 模块类型声明:当你自己编写JavaScript文件但希望在TypeScript项目中使用它们时,可以通过编写
.d.ts文件为这些模块提供类型说明。
TypeScript编译配置
通过tsconfig.json文件配置TypeScript的编译选项compilerOptions。
- target:指定 TypeScript 编译后输出的 JavaScript 版本。例如:
"target": "ES5"、"target": "ES6"、"target": "ESNext"。 - module:指定模块系统,决定了如何处理模块导入导出。例如:
"module": "commonjs"、"module": "esnext"、"module": "amd"。 - strict:当为true时,开启严格模式,包含多种严格检查选项的组合。
- outDir:指定编译后输出文件的目录。
- rootDir:指定包含源码的目录,编译器会在此目录下查找
.ts文件。 - allowJs:允许编译
.js文件(JavaScript 文件)。 - sourceMap:生成
.map文件,用于调试时将编译后的JavaScript映射回原始TypeScript。 - noEmitOnError:默认值为true,当代码中存在编译错误时,TypeScript 编译器不会生成输出文件(即不会将 .ts 文件编译成 .js 文件)。
- noImplicitAny:当为true时,将对类型被隐式推断为 any 的任何变量发出错误警告。
- strictNullChecks:当为true时,会对null和undefined进行提醒。
- strictPropertyInitialization:设置控制类字段是否需要在构造函数中初始化。
- useDefineForClassFields:类字段将在父类构造函数完成后初始化,覆盖父类设置的任何值。
- declaration:当为true时,TypeScript编译器会为每个.ts文件生成相应的 .d.ts 文件。
- skipLibCheck:跳过对
.d.ts声明文件的类型检查,可以提高编译速度,但可能会隐藏一些类型错误。 - removeComments:移除编译后生成的 JavaScript 文件中的注释。
- esModuleInterop:允许与 CommonJS 和 ES 模块更好的互操作,主要用于处理 default 导出。
- moduleResolution:决定模块的解析策略,有两种模式:node(基于 Node.js 模块解析)和 classic(TypeScript 原有的解析方式)。
- lib:指定要包含的内置库,默认包含常用的 JavaScript 运行时库,比如 ES6、DOM 等。
- paths:配置模块导入的路径映射,常用于别名路径。
- baseUrl:配合 paths 使用,指定相对模块导入的基准目录。
- jsx:指定如何处理 JSX 语法。常用值为 "react" 或 "react-jsx",用于 React 项目。
{
"compilerOptions": {
"target": "ES6",
"module": "commonjs",
"strict": true,
"outDir": "./dist",
"rootDir": "./src",
"sourceMap": true,
"declaration": true,
"noImplicitAny": true,
"esModuleInterop": true,
"skipLibCheck": true,
"lib": ["ES6", "DOM"],
"moduleResolution": "node",
"paths": {
"@utils/*": ["src/utils/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.test.ts"]
}注释命令
TypeSciript注释命令是指采用JS双斜杠注释形式的命令,它可以向编译器发出命令。
// @ts-nocheck:告诉编译器不对当前脚本进行类型检查。// @ts-check:告诉编译器对当前脚本进行类型检查。// @ts-ignore:告诉编译器不对下一行代码进行类型检查。// @ts-expect-error:告诉编译器,即使下一行代码有类型错误也不提示,将错误交由代码处理。
快查表
控制流分析

接口

类型

类
