💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# TypeScript https://mp.weixin.qq.com/s/lkEKHBU4dqJ_9qbJJnBiPA https://juejin.cn/post/6872111128135073806#heading-98 ``` // 安装最新版typescript npm i -g typescript // 安装ts-node npm i -g ts-node // 创建tsconfig.json tsc --init // 新建index.ts,执行 ts-node index.ts ``` ### interface和type区别 https://blog.csdn.net/qq_41499782/article/details/112569228 **不同点:** * 扩展继承语法: interface使用extends,type使用‘&’ * 接口可以被类实现,而类型别名不可以 * 同名合并:interface 支持,type 不支持。 * 描述类型:对象、函数两者都适用,但是 type 可以用于基础类型、联合类型、元祖。 * 计算属性:type 支持计算属性,通过in来实现类型映射,;interface 不支持。 **相同点:** * 两者都可以用来描述对象或函数的类型 * 两者都可以实现继承 总的来说,公共的用 interface 实现,不能用 interface 实现的再用 type 实现。 ```js // 合并声明 -- 接口定义一个名字,后面的接口可直接使用这个名字,自动合并所有的声明,类似继承 // 扩展的方式:类型别名也可以进行扩展,使用 &符号进行(这个继承是合并关系,如果父级有了一个类型,子集还可以声明,但是类型就是变成 &;)这个叫做交叉类型。 // 虽然说 类型别名可以 这样父级和子级声明相同的类型,但是在类型检查会类型推导成其他的,这样使用可能会导致定义的类型与预期不符合。可能合并成 never 类型。 // 类型映射 -- 通过 in来实现类型映射 type Keys = "firstname" | "lastname" type DudeType = { [key in Keys]: string } const test: DudeType = { firstname: "323", lastname: "332" } // 类型别名 可以使用 typeof 获取实例的 类型进行赋值 let div = document.createElement('div'); type B = typeof div ``` ## **基础数据类型** TypeScript的原始类型(number、string、bigint、boolean、symbol、null、undefined、object) 对应JavaScript8 种内置类型:Number、String、BigInt、Boolean、Symbol、Null、Undefined、Object TypeScript还定义了:unknown、never、void、数组、元组、函数等 tsconfig.json指定了"strictNullChecks":true ,null 和 undefined 只能赋值给 void 和它们各自的类型 number和bigint都表示数字,但是这两个类型不兼容,不能互相赋值 ```js let str: string = "jimmy"; let num: number = 24; let bool: boolean = false; let u: undefined = undefined; let n: null = null; let obj: object = { x: 1 }; let big: bigint = 100n; let sym: symbol = Symbol("me"); // *********** 定义数组 ********************** let arr:string[] = ["1","2"]; let arr2:Array<string> = ["1","2"]; // 定义联合类型数组 let arr:(number | string)[]; // 定义指定对象成员的数组 interface Arrobj{ name:string, age:number } let arr3:Arrobj[]=[{name:'jimmy',age:22}] // *********** Tuple元组:表示已知元素数量和类型的数组,长度已指定 ************ let x: [string, number]; // x = ['hello', 10]; // OK x = [10, 'hello']; // Error // 解构赋值 let employee: [number, string] = [1, "Semlinker"]; let [id, username] = employee; // 可选元素 -- ?号声明可选元素 type Point = [number, number?, number?]; const xy: Point = [10, 20]; // 二维坐标点 // 剩余元素 type RestTupleType = [number, ...string[]]; let restTuple: RestTupleType = [666, "Semlinker", "Kakuqo", "Lolo"]; // 只读的元组类型 const point: readonly [number, number] = [10, 20]; // *********** void ********************** let a: void; let b: number = a; // Error // strictNullChecks未指定为true, void类型只能赋予null和undefined function fun(): undefined { console.log("this is TypeScript"); }; fun(); // Error,方法没有返回值得到undefined,但是需定义成void类型 // *********** never ********************** // never类型表示的是那些永不存在的值的类型 // 函数执行时抛出了异常,该函数永远不存在返回值 // 函数中执行无限循环的代码--死循环 // never类型同null和undefined一样,是任何类型的子类型,可赋值给任何类型 // 任何类型都不能赋值给never类型,除了never本身,any也不行 // *********** any ********************** // 允许被赋值为任意类型,在any上访问任何属性都是允许的,也允许调用任何方法 let anyThing: any = 'Tom'; anyThing.setName('Jerry'); anyThing.setName('Jerry').sayHello(); // 无法使用 TypeScript 提供的保护机制 // *********** unknown ********************** // unknown与any的最大区别是:任何类型的值可以赋值给any,any类型的值也可赋值给任何类型。 // 任何类型的值都可以赋值给unknown,但它只能赋值给unknown和any // *********** object、Object 和 {} ********************** // object 是一个宽泛的通用的非基本类型 let foo: { [key: string]: string } = {}; let bar: object = {}; bar = foo; // OK // 不能将类型 object 分配给类型 { [key: string]: string; } foo = bar; // Error // Object 接口(类型) 用于定义 JS Object 的原型对象Object.prototype // ObjectConstructor 用于定义 Object 自身的属性,如Object.create() // Object 的所有实例都继承了 Object 接口的所有属性/方法 ``` - object 是TypeScript v2.2引入的一种非基本类型,表示任何非原始值类型,包括对象、函数、数组等;不能被赋予原始值。 - Object 是对TypeScript对JavaScript Object.prototype原型对象的定义,是所属对象类型的顶层类型,即所有对象类型都继承了Object中定义的属性/方法。 JavaScript的装箱拆箱机制,基本类型有能力访问Object.prototype原型对象上的属性。。 - {} 是一个没有任何成员的对象类型,它可以访问Object中定义的属性/方法,也可以被赋予原始值。 虽然 Object 和 {} 都可以接受基本类型的值,但并不包括 null 和 undefined ## **函数** ```js // 函数声明 function sum(x: number, y: number): number { return x + y; } // 函数表达式:限制等号左侧的类型,对函数名赋值时保证参数个数和类型、返回值类型不变。 let mySum: (x: number, y: number) => number = function (x: number, y: number): number { return x + y; }; // 用接口定义函数类型 interface SearchFunc{ (source: string, subString: string): boolean; } // 可选参数--可选参数后面不允许再出现必需参数 function buildName(firstName: string, lastName?: string) { lastName ? return firstName + ' ' + lastName : return firstName; } let tomcat = buildName('Tom', 'Cat'); let tom = buildName('Tom'); // 参数默认值 function buildName(firstName: string, lastName: string = 'Cat') { return firstName + ' ' + lastName; } // 剩余参数 function push(array: any[], ...items: any[]) { items.forEach(function(item) { array.push(item); }); } let a = []; push(a, 1, 2, 3); // 函数重载或方法重载----使用相同名称和不同参数数量或类型创建多个方法 function add(a: number, b: number): number; function add(a: string, b: string): string; function add(a: string, b: number): string; function add(a: number, b: string): string; function add(a: Combinable, b: Combinable) { // type Combinable = string | number; if (typeof a === 'string' || typeof b === 'string') { return a.toString() + b.toString(); } return a + b; } class Calculator { add(a: Combinable, b: Combinable) { if (typeof a === 'string' || typeof b === 'string') { return a.toString() + b.toString(); } return a + b; } } const calculator = new Calculator(); const result = calculator.add('Semlinker', ' Kakuqo'); ``` ### 类型守卫 - 类型判断:`typeof` - 实例判断:`instanceof` - 属性判断:`in` - 字面量相等判断:`==`,`===`,`!=`,`!==` ### 类型断言(尖括号/as) 定义一个变量时,起初不知道类型,但使用过程知道是什么类型--->用到类型断言了。 ```js const str = '测试' const resLength : number = (<string>str).length const resLength : number = (str as string).length // 非空断言 (x! 将从 x 值域中排除 null 和 undefined) function myFunc(maybeString: string | undefined | null) { const onlyString: string = maybeString; // Error const ignoreUndefinedAndNull: string = maybeString!; // Ok } // 确定赋值断言 ``` ## 接口(Interfaces) 使用接口(Interfaces)来定义对象的类型 ```js // 可选、只读、任意属性(索引签名 - 实现) interface Person { name: string; age?: number; [propName: string]: any; } const p1 = { name: "semlinker" }; const p2 = { name: "lolo", age: 5 }; const p3 = { name: "kakuqo", sex: 1 } ``` 接口之间可以互相继承 、接口继承类 当接口继承了一个类,那么接口也会拥有类的属性和方法。当别的类 实现这个 接口时,会同时实现 接口的属性和方法, 继承类的属性和方法 ### type 和 interface type 不支持继承和声明合并, interface 可以; type 更为通用, 右侧可以是任意类型, interface 主要用于定义对象; type 和 interface 均可使用的情况下使用 interface; ## **TypeScript 类** ```js class Greeter { // 静态属性 static cname: string = "Greeter"; // 成员属性 greeting: string; // 构造函数 - 执行初始化操作 constructor(message: string) { this.greeting = message; } // 静态方法(static关键字),静态方法不能调成员属性,可调用静态属性 static getClassName() { return "Class name is Greeter"; } // 成员方法 greet() { return "Hello, " + this.greeting; } } let greeter = new Greeter("world"); ``` 成员属性与静态属性,成员方法与静态方法有什么区别 成员方法在实例的prototype上 **封装,继承,多态** - **类---修饰符(public、protected、private)**   public:公有,不加修饰符默认公有。类里、子类、外部可以访问   protected:保护类型,类里、子类可以访问,类外不可访问   private:类里可以访问,子类、外部不可访问 - **继承 (extends、super)** ```js class Animal { name: string; constructor(theName: string) { this.name = theName; } move(distance: number = 0) { console.log(`${this.name} moved ${distance}m.`); } } class Snake extends Animal { constructor(name: string) { super(name); } // 调用父类的构造函数 move(distance = 5) { console.log("Slithering..."); super.move(distance); } } let sam = new Snake("Sammy the Python"); sam.move(); ``` **多态**是属于继承的一种:父类定义一个方法不去实现,让继承它的子类去实现 **类方法重载** ```js class ProductService { getProducts(id?: number) { if(typeof id === 'number') { console.log(`获取id为 ${id} 的产品信息`); } else { console.log(`获取所有的产品信息`); } } } const productService = new ProductService(); productService.getProducts(666); // 获取id为 666 的产品信息 productService.getProducts(); // 获取所有的产品信息 ``` - 抽象方法和抽象类 抽象类只能被继承,不能被实例化;定义抽象类使用abstract关键字;抽象方法只能放在抽象类中 ```js abstract class Hello { public name:string constructor(name:string){ this.name =name } abstract eat():any //继承Hello这个类的子类必须要有eat(){}函数 run(){} } class Word extends Hello{ constructor(name:string){ super(name) } eat(){} } ``` ### 泛型(Generics) 泛型(Generics):允许同一个函数接受不同类型参数的一种模板, 相比 any 类型,泛型会保留参数类型。 **类型变量**通常使用T---Type;K--对象中的键Key;V--对象中的值Value;E--元素Element。 ```js function identity <T, U>(value: T, message: U) : T { return value; } console.log(identity<Number, string>(68, "Semlinker")); console.log(identity(68, "Semlinker")); // 省略尖括号,使编译器自动选择类型 // 泛型接口 interface GenericIdentityFn<T> { (arg: T): T; } // 泛型类 class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function (x, y) { return x+y } ``` 语法糖`Partial<T>` 的作用就是将某个类型里的属性全部变为可选项 ? ```js type Partial<T> = { [P in keyof T]?: T[P] } // 通过 keyof T 拿到 T 的所有属性名,T[P] 取得相应属性值,中间的 ? 号将所有属性变为可选 interface UserInfo { id: string; name: string; } const xiaoming: UserInfo = { name: 'xiaoming' } // error, 还缺一个属性没定义 type NewUserInfo = Partial<UserInfo>; const xiaoming: NewUserInfo = { name: 'xiaoming' } // 相当于 interface NewUserInfo{ id?: string; name?: string } ``` ### 装饰器 装饰器的分类:类装饰器、属性装饰器、方法装饰器、参数装饰器 装饰器函数有三个参数: target —— 当前对象的原型,也就是说,假设 Employee 是对象,那么 target 就是 Employee.prototype propertyKey —— 方法的名称 descriptor —— 方法的属性描述符,即 Object.getOwnPropertyDescriptor(Employee.prototype, propertyKey)