前言
❝大家都知道Vue3开始全面支持Typescript,而且ts本身支持es5和es6写法,所以学起来其实并不复杂,难度大概和刚开始js学完学es6难度差不多,趁着这两天有时间,自己总结下,欢迎评论留言交流,如有不对的地方,会及时更正,还望见谅,这些都是我个人笔记总结的
❞
- ts有点多 这肯定是个体力活 希望大家能给个三连 >B<
TS铺垫
TS的优势
TypeScript 的优势和收益是什么?
- 类型系统可在编译阶段发现大部ipt 降低了使用成本
TS安装
- 1.安装 TypeScript
$ npm install -g typescript
- 2.编译 TypeScript 文件
$ tsc helloworld.ts
TS的基本类型
number数字类型
let count: number = 666;
// ES5:var count = 666;
String字符串类型
let csgo: string = "rush B";
// ES5:var csgo = 'rush B';
Boolean 类型
let isOver: boolean = true;
// ES5:var isOver = true;
Array数组类型
let arr: number[] = [1, 2, 3];
// ES5:var arr = [1,2,3];
let arr: Array<number> = [1, 2, 3]; // Array<number>泛型语法
// ES5:var arr = [1,2,3];
Object对象类型
const obj:object={}
❝以上在js类型中也有,那么下面介绍下ts比js多出的一些类型
❞
Any 任何类型
「在 TypeScript 中,任何类型都可以被归为 any 类型。」 能被任何人赋值
let coco: any = 666;
coco = "字符串也可以哦";
coco = false;
Enum 枚举类型
「理解为存常量的特殊对象即可」
enum Animal {
CAT = 'cat',
DOG = 'dog',
MOUSE = 123,
}
console.log( Animal.CAT )//cat
console.log(Animal['CAT'])//cat
❝枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:
❞
enum Days {Sun, Mon, Tue, Wed, Thu};
console.log(Days["Sun"] === 0); // true
console.log(Days["Mon"] === 1); // true
console.log(Days["Thu"] === 4); // true
console.log(Days[0] === "Sun"); // true
console.log(Days[1] === "Mon"); // true
console.log(Days[2] === "Tue"); // true
当然你也可以设置初始值
enum Days {Sun = 3, Mon = 1, Tue, Wed, Thu, Fri, Sat};
Unknown 未知类型
❝就像所有类型都可以被归为 any,所有类型也都可以被归为 unknown any用来约束 ,而 unknown用来断定为不确定值
❞
let value: unknown;
value = true; // OK
value = 42; // OK
//和any好像?
「未知类型只能赋值给自身以及any」
let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error
Tuple 元祖类型
「固定长度,固定类型」
let tup: [number, string] = [27, "jianan"];
console.log(tup);//let tup: [number, string]
Void 空类型
「约束函数的返回值,表示该函数没有返回任何值 也就是 不return」
// 声明函数返回值为void
function warnUser(): void {
console.log("不会return任何东西");
}
Never 永不存在值类型
「 表示该函数永远不会结束 比如报错类型语句 死循环」
function error(message: string): never {
throw new Error(message);
}
❝接下来我们补充一些关键字,以便我们学习Type和接口以及泛型能够更好地理解
❞
断言
「也就是强制性的修改其数据类型」
类型断言as
as断言
<断言>值
let someValue: any = "this is a string";
// 'as'语法:值 as 类型
let strLength: number = (someValue as string).length;
// '尖括号'语法:<类型>值
let strLength2: number = (<string>someValue).length;
非空断言
「确定其有值,不会null和undefiend」
function sayHello2(name: string | undefined) {
let sname: string = name!;//!感叹号哦 就这个
}
类型判断
typeof 类型演算
const a: number = 3
// 相当于: const b: number = 4
const b: typeof a = 4
instanceof 推断类型
let obj = 0.5 < Math.random() ? new String(1) : new Array(1);
if(obj instanceof String){
// obj推断为String类型
obj+= '123'
} else {
// obj为any[]类型
obj.push(123);
}
类型别名 和 接口
「这2个算是TS中比较重要用的也较多的,都可以用于约束 类、对象、函数的契约」
「先来写简单的」
type one = {
name: string,
age: number
}
let obj: one = {
name: '嘤嘤嘤',
age: 18
}
再看看接口
interface two {
love: string,
disg: () => boolean
}
let obj: two = {
love: '勒布朗詹姆斯',
disg: () => true
}
- Type和interface非常的相似 再看看他们应用在各种类型上如何约束↓
约束类
interface ClockInterface { // 同理type也可以 type ClockInterface={}
currentTime: Date;
setTime(d: Date): string;
}
class Clock implements ClockInterface {
public currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
return '嘿嘿嘿'
}
constructor(h: number, m: number) { }
}
约束对象
type和interface都可以
interface Husband { //type Husband ={}
sex:string
interest:string
age:number
}
let myhusband:Husband ={ sex:'男',interest:'看书、作家务',age:18}
约束函数
//type和interface都可以
interface SearchFunc { //type SearchFunc={}
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc = (source, subString) => {
return true;
}
约束数组
//type和interface都可以
interface NumberArray { //type NumberArray = {}
[index: number]: number;
}
let fibonacci: NumberArray = [1, 1, 2, 3, 5];
约束对象 属性值和属性名
//type和interface都可以
interface Dictionary<T> { //type Dictionary = {}
[index: string]: T; //属性名:string : 属性值外界定
};
const data:Dictionary<number> = {
a: 3,
b: 4
}
类型别名和接口的区别
继承方法不同
❝Type是使用交叉类型&进行继承,而interface使用的是extends 他们还能互相继承?
❞
- 接口 继承 接口(extends)
interface Name {
name: string;
}
interface User extends Name {
age: number;
}
const obj:User={
name:'123',
age:321
}
- 别名 继承 别名 (&)
type Name = {
name: string;
}
type User = Name & { age: number };
const obj:User={
name:'123',
age:321
}
- 接口 继承 别名
type Name = {
name: string;
}
interface User extends Name {
age: number;
}
const obj:User={
name:'123',
age:321
}
- 别名 继承 接口
interface Name {
name: string;
}
type User = {
age: number;
}& Name
const obj:User={
name:'123',
age:321
}
接口可以而别名不行的
「interface有个特性,就是多次声明会进行合并」
interface User {
name: string
age: number
}
interface User {
sex: string
}
/*
User 接口为 {
name: string
age: number
sex: string
}
*/
别名可以而接口不行的
「type可以声明 基本类型,联合类型,元组 的别名,interface不行」
// 基本类型别名
type Name = string
// 联合类型
interface Dog {
wong();
}
interface Cat {
miao();
}
type Pet = Dog | Cat
// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]
//interface why = Pet|PetList //error
「type 支持类型映射,interface不支持」 支持映射的type成为了泛型的宠儿
type Keys = "firstname" | "surname"
type DudeType = {
[key in Keys]: string
}
const test: DudeType = {
firstname: "Pawel",
surname: "Grzybek"
}
// 报错
//interface DudeType {
// [key in keys]: string
//}
TS中的类
「在 TypeScript 中,我们可以通过 Class 关键字来定义一个类:」
class rushB {
// 静态属性
static cname: string = "rushB";
// 成员属性
heihei: string;
// 构造函数 - 执行初始化操作
constructor(message: string) {
this.heihei = message;
}
// 静态方法
static getClassName() {
return "A1高闪来一个";
}
// 成员方法
greet() {
return "我就喜欢, " + this.heihei;
}
}
let obj = new rushB("哈哈哈");
访问权限修饰符
- public: 默认的, 公开的,所有代码都能在内外访问到
- private 私有的, 只有在类中才可以访问
- protected 受保护的修饰符(只能在自身和派生类(子类)中访问到)
- static : 它们不需要实例化,而是直接通过类来调用:
class Hello {
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public name: string; // 这个是对后文this.name类型的定义
public age: number;
private password: '这是私有的,只有我自己能访问'
protected file:'这个只有我活着继承我的子类可以访问'
print() {
return this.name + this.age;
}
}
let hello = new Hello('name', 18);
存取器
「设置器set / 读取器get 控制属性的读取和赋值」
class Hello {
private _age: number;
get age(): number {
return this._age;
}
set age(age: number) {
if (age > 0 && age < 100) {
console.log("年龄在0-100之间"); // 年龄在0-100之间
return;
}
this._age = age;
}
}
let hello = new Hello();
hello.age = 23;
console.log(hello.age)
类继承+约束
interface A {
age: number
}
class B {
constructor(name: string) {
this.name = name;
}
name: string
}
class C extends B implements A {
constructor() {
super('BBBBBB')
}
age = 123;
tell() { console.log(this.age, this.name) }
}
let hh = new C()
hh.tell();//123 BBBBBB
补充关键字
❝接下来准备泛型了 算是TS中的重量级选手 我们需要补充一些知识点
❞
keyof 获取类型约束
interface Point {
x: number;
y: number;
}
type keys = keyof Point;// type keys = "x" | "y"
in 配合keyof可以进行遍历
interface Duck {
age: 10
name: 'duck'
}
type obj = {
[p in keyof Duck]: Duck[p] // age: 10 name: 'duck'
}
❝下面2个用到了泛型 大家可以先去泛型看完再回头看,因为我不想又分开来免得大家来回跑
❞
extends 继承
「extends 可以用来继承一个类,也可以用来继承一个 interface,但还可以用来判断有条件类型」
T extends U ? X : Y;
- 用来表示类型是不确定的, 如果U的类型可以表示T, 那么返回X, 否则Y.
- 挺绕的那看看这个把
type Words = 'a'|'b'|"c";
type W<T> = T extends Words ? true : false;
type WA = W<'a'>; // -> true
type WD = W<'d'>; // -> false
「a 可以赋值给 Words 类型,所以 WA 为 true,而 d 不能赋值给 Words 类型,所以 WD 为 false。」
infer 类型推导
「就是字面意思 推断,柯南,懂? -.-」
- 看看源码实现
type ReturnType<T> = T extends (
...args: any[]
) => infer R
? R
: any;
「其实这里的 infer R 就是声明一个变量来承载传入函数签名的返回值类型, 简单说就是用它取到函数返回值的类型方便之后使用。」
❝我自己把自己写懵了,上面话我自己都听不太懂,话说infer真的难理解,看看下面的例子
❞
T extends (...args: infer P) => any ? P : never;
- 上面声明一个P用来表示...args可能的类型,
- 如果(...args: infer P)可以表示 T, 那么返回...args对应的类型, 也就是函数的参数类型, 反之返回never.
- 更好理解的是 infer P 他接收了P 并且无论如何都返回 因为他的判定条件为any 肯定返回 「说实话我不知道是不是这样理解的,我只能大概的理解成这样,希望大佬看到能完善下小弟的意思」
泛型
「泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持」
- 来看看怎么用的吧 冲冲冲
2种定义泛型方式
function gen_func1<T>(arg: T): T {
return arg;
}
let gen_func2: <T>(arg: T) => T = function (arg) {
return arg;
}
使用泛型
function identity <T>(value: T) : T {
return value;
}
console.log(identity<Number>(1)) // 1 Number传入到了 identity中的所有T中
多泛型
「这里的返回值还用到了联合类型哦」
function CSGO <T, U>(value: T, message: U) : T|U {
console.log(message);
return value;
}
console.log(CSGO<Number, string>(66, "RushB"));
泛型接口/别名
- 类型别名和接口差不多的
interface CSGO<V, M> {
target: V,
message: M
}
let obj: CSGO<string, number> = {
target: 'B',
message: 666
}
泛型类
interface GenericInterface<U> {
value: U
getIdentity: () => U
}
class IdentityClass<T> implements GenericInterface<T> {
value: T
constructor(value: T) {
this.value = value
}
getIdentity(): T {
return this.value
}
}
const myNumberClass = new IdentityClass<Number>(24);
console.log(myNumberClass.getIdentity()); // 24
const myStringClass = new IdentityClass<string>("累了,复制粘贴例子算了!");
console.log(myStringClass.getIdentity()); // 累了,复制粘贴例子算了!
泛型参数默认类型
interface A<T=string> {
name: T;
}
const strA: A = { name: "老八蜜汁小伙伴" };
const numB: A<number> = { name: 404 };
泛型工具类型
「这里就开始舒服起来了,封装了许多好用的」
Partial 将类型T的成员变为可选
interface User {
id: number;
};
// 相当于: type PickUser = { id?: number}
type PickUser = Partial<User>
//实现原理//
type Partial<T> = {//所有为可选-?
[P in keyof T]?: T[P];
};
Required 将类型T中的成员变为必填
type User = {
id: number;
};
// 相当于: type PickUser = { id: number}
type PickUser = Partial<User>
//实现原理//
type Partial1<T> = { //所有为必选
[P in keyof T]-?: T[P];
};
Readonly 将类型T中的成员变为只读
//使用方式
type PickUser = Readonly<User>
//实现原理//
type Partial1<T> = { //所有为必选
readonly[P in keyof T]: T[P];
};
Exclude<T,U> 抽离出T可以给U赋值的值
``` js
//使用方法 type A = Exclude<'x' | 'a', 'x' | 'y' | 'z'> //type A = 'a'
//实现原理// type Exclude<T, U> = T extends U ? never : T;
## Extract<T,U> 抽离出T和U的共同值
``` js
type A = Extract<'x' | 'a' | 'c', 'x' | 'y' | 'a'>
//type A = 'x'|'a'
//实现原理//
type Extract<T, U> = T extends U ? T : never;
ReadonlyArray 使数组变为不可赋值
let arr: ReadonlyArray<string> = ["a", "b"];
//arr:readonly string[]
arr.push("c"); // error
arr[0] = "c"; // error
NonNullable 去除T中的null和undefined
``` js
type User = 'a' | 'b' | null | undefined
type aaa = NonNullable // aaa = 'a'|'b'
## Parameters<T>获取函数参数的类型,返回数组形式
```js
function cba(a: number, b: string) {return a + b}
type nba = Parameterss<typeof cba>
//nba = [number,string]
//实现原理//
type Parameterss<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
ConstructorParameters获取class构造函数的参数类型,返回数组形式
class abc{}
type aaa= new(a:number ,b:any)=> abc
type nba = ConstructorParameters<aaa>
//nba = [number,any]
ReturnType 获取函数 返回值 类型
function abc(a: number, b: number) {
return `${a + b}`//string
}
type cba = ReturnType<typeof abc>//typeof判断返回值为string
//cba=string
//实现原理//
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
InstanceType获取构造函数类型的实例成员
//例子1class Animal {}
type Result = InstanceType<typeof Animal>;//类型为Animal
//例子2
class abc{}
type z = new()=>abc
type Result2 = InstanceType<z>;//类型为abc
ThisType 设置对象的this
interface Person {
name: string
age: number
}
//[k: string]: any 对象的每一位属性名为字符串 属性值为anyZ
type ObjType = { [k: string]: any } & ThisType<Person>
const obj: ObjType = {
a:1,
method(arg1: boolean) {
// this的类型被约束为Person
console.log(this.age)
}
}
Omit<T,K> 将K属性从T校验对象中剔除掉
interface User {
id: number;
age: number;
name: string;
};
// 将id从校验对象中剔除 相当于: type PickUser = { age: number; name: string; }
type OmitUser = Omit<User, "id">
//实现原理//
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
Pick<T,K>, 只保留自己选择的属性, K代表要保留的属性键值
这个有什么意义不懂
type A = Pick<{a:number,b:string,c:boolean}, 'a'|'b'>
type A1 = Pick<A, 'a'|'b'> // {a:number,b:string}
❝中午1点到现在,接近4小时终于完成了,TS真的是多,希望可以帮到大家,这些是我学习ts记录的笔记分享给大家 (^▽^) 给个三连哦