ts整理

基本类型

  1. 类型声明:通过类型声明可以指定ts中变量(参数、形参)的类型,指定类型后,当为变量赋值时,ts编辑器会自动检查值是否符合类型声明,不符合就报错;

  2. 如果变量的声明和赋值是同时进行的,ts可以自动对变量进行类型检查;

    let c: boolean = false;  // :boolean 就是类型注解
    let x = true;  //自动检查x变量为布尔值
    x = 3;  //会报错
    
    
    function sum(a:number, b:number): number{     //限制参数和返回值的类型
    	return a + b;
    }
    sum(123,'456'789); //第二个参数报错,传递的应该是一个数字而非字符串; 第三个参数报错,因为函数限制了两个
    
    
  3. 类型:

    类型描述
    number任意数字
    string任意字符串
    boolean布尔值
    字面量限制变量的值就是该字面量的值
    any任意类型
    unknown1类型安全的any
    void没有值(或者undefined)
    never不能是任何值
    object任意的js对象
    array任意的js数组
    tuple元组,固定长度数组
    enum枚举类型
  4. 语法

    let 变量: 类型
    let 变量:类型 = 值
    function fn(参数:类型,参数:类型):类型{
    	...
    }
    
  5. 联合类型

    let c: boolean | string;
    c = true;
    c = 'hello';
    
    
  6. any类型 ,相当于对该变量关闭了ts校验,不建议使用;声明变量如果不指定类型,则ts解析器会自动判断变量的类型为any,避免使用;如果类型不确定可以用any,但还有一个解决方法,用unknown;

    let e: unkown;
    let s:string;
    e = 'hello'
    
    // unkown 实际上就是一个类型安全的any
    // unkown 类型的变量,不能直接赋值给其他变量
    if(typeof e === 'string'){
    	s = e;
    }
    
    // 类型断言,可以用来告诉解析器变量的实际类型
    /**
    语法:
    	变量 as 类型
    	<类型>变量
    */
    s = e as string;
    s = <string>e;
    
    
  7. object 类型,一般不去限制是不是一个对象,而是去限制对象里的属性;

    let b: {name:string,age?:number};  //在属性名后加上一个?,表示是可选属性,可有可无
    b = {name: '孙悟空'}let c: {name:string,[propName: string]: any};  //如果只想限制name,其他可有可无,则可以用[propName:string]:any 如果想限制值的类型,可把any换成其他类型4
    c = {name:'猪八戒',age:18, gender:'man'}
    
    
  8. 数组

    语法:
    	数组的类型声明:
    		类型[]
    		Array<类型>
    
    let e: string[];    //string[] 表示字符串数组
    e = ['a','b',1];    //第三个参数1飘红报错,因为限制了数组里的值只能是字符串
    
    let g: Array<number>;  //表示数值数组,限制值只能为数值
    
    
  9. 元组tuple :就是固定长度的数组

    语法:[类型,类型,类型]
    
    let h: [string,string]
    h = ['nihao']  //飘红,因为需要两个,但这块只传了一个
    
    
  10. enum 枚举

    enum Gender{
    	Male = 0;
    	Female = 1;
    }
    
    let i: {name: string, gender: Gender}
    i = {
    	name: '孙悟空',
    	gender:Gender.Male //'male'
    }
    console.log(i.gender === Gender.Male)
    
    
  11. 类型的别名

    type myStr = string
    let s:myStr //等同let s: string
    
    let myType = 1 | 2 | 3 | 4 | 5
    let k: myTyppe;
    let l: myType
    
    

运算符

非空断言运算符

用在变量或函数名之后,用来强调对应的元素是非null | undefined的,这个符号的场景,特别适用于我们已经明确知道不会返回空值的场景,从而减少冗余的代码判断

可选链运算符 ?.

?.用来判断左侧的表达式是否是 null | undefined,如果是则会停止表达式运行,可以减少我们大量的&&运算。

空值合并运算符 ??

??与||的功能是相似的,区别在于 ??在左侧表达式结果为 null 或者 undefined 时,才会返回右侧表达式 。

数字分隔符_

_可以用来对长数字做任意的分隔,主要设计是为了便于数字的阅读,编译出来的代码是没有下划线的,请放心食用。

操作符

keyof是索引类型查询操作符

keyof 可以获取一个类型所有键值,返回一个联合类型

type Person {
	name: string,
	age: number
}
type PersonKey = keyof Person   // PersonKey得到的类型为 'name' | 'age'

keyof 的一个典型用途是限制访问对象的 key 合法化,因为 any 做索引是不被接受的。

function getValue (p: Person, k: keyof Person){
	return p[k]  // 如果k不如此定义,则无法以p[k]的代码格式通过编译
}

总结起来 keyof 的语法格式如下

类型 = keyof 类型
实例类型获取typeof

typeof 是获取一个对象/实例的类型,如下:

const me: Person = {name: 'healer', age:16};
type P = typeof me; // { name: string, age: number | undefined }
const you: typeof me = {name: 'mama',age: 69}  // 可以通过编译

typeof 只能用在具体的对象上,这与 js 中的 typeof 是一致的,并且它会根据左侧值自动决定应该执行哪种行为。

const typestr = typeof me;   // typestr的值为"object"

typeof 可以和 keyof 一起使用(因为 typeof 是返回一个类型嘛),如下

type PersonKey = keyof typeof me;   // 'name' | 'age'

总结起来 typeof 的语法格式如下:

类型 = typeof 实例对象
遍历属性in

in 只能用在类型的定义中,可以对枚举类型进行遍历,如下:

// 这个类型可以将任何类型的键值转化成number类型
type TypeToNumber<T> = {
	[key in keyof T]: number
}

keyof返回泛型 T 的所有键枚举类型,key是自定义的任何变量名,中间用in链接,外围用[]包裹起来(这个是固定搭配),冒号右侧number将所有的key定义为number类型。

于是可以这样使用了:

const obj: TypeToNumver<Person> = {name: 10, age: 10}

总结起来 in 的语法格式如下:

[ 自定义变量名 in 枚举类型 ]: 类型

面向对象

万物皆对象: 属性 + 方法

  1. class 类名{
    	属性名: 类型;
    	
    	constructor(参数:类型){
    		this.属性名 = 参数;
    	}
    	
    	方法名(){
    		...
    	}
    }
    
    class Person{
    	// 实例属性 - 通过对象访问
    	name: string
    	age: number
    	//静态属性 - 通过类访问
    	static stic: number = 18//构造函数 - new一个对象的时候执行
    	constructor(name: string, age: number){
    		this.dog = dog
    		this.dogAge = age
    	}
    	
    	//方法,一般放原型上
    	bark(){
    		console.log('汪汪汪')
    	}		
    }
    
    const per = new Person()
    
    
  2. 继承 - 抽取公共代码

    使用extends关键字继承父类的属性和方法

    使用super关键字

    class Dog extends Animal{
    	sayHello(){
    		super.sayHello()  //调用父类的方法
    	}	
    }
    
    constructor(name:string, age: number){
    	super(name)    // 调用父类的构造函数
    	this.age = age
    }
    
  3. 抽象类

    比如说Animal作为一个基类,而它的子类Dog才是真正用来创建对象的,如果说不希望使用Animal去创建对象,那么在基类前加 abstract关键字

    抽象类就是专门用来被继承的类,不能创建实例对象

    抽象类可以用来创建对象方法,抽象方法使用abstract关键字开头,没有方法它,,返回void,抽象方法只能定义在抽象类中,子类必须对抽象方法进行重写

接口

  1. 接口用来定义一个类结构 关键字interface
    // 描述一个对象的类型
    type myType = {
    	name: string,
    	age: number
    }
    
    // 描述用来定义一个类结构
    interface myInterface{
    	name: string;
    	age: number;
    	sayHello():void
    }
    
  2. 接口可重复声明,它会合并
  3. 定义类时,可以使用类去实现一个接口,实现接口就是使类满足接口的要求
    class MyClass implements myInter{
    	name: string;
    	
    	constructor(name: string){
    		this.name = name
    	}
    	
    	sayHello(){
    		console.log('你好')
    	}
    }
    

属性的封装

ts在属性前添加属性的修饰符

  • public 公有属性 (直接访问,可读可修改)
  • private 私有属性 (只有在类里面访问,外面访问不到,不能直接获取属性,可以定义一个方法用来访问)
  • protect 保护属性(只能在当前类和子类中访问,外部不能访问)

泛型

定义函数或者类时,如果遇到类型不明确时,可以使用泛型

// T表示任意类型,只有函数执行时才知道时什么类型。T也可以叫其他名字,任取
function fn<T>(a:T):T

let res1 = fn(a:10);  //不指定泛型,ts会自动推断
let res2 = fn<string>(a:'hello')  //指定泛型

// 泛型还可以同时指定多个
function fn2<T,K>(a: T, b:K):T{
	console.log(b);
	return a;
}
fn2<number,string>(a:123, b:'hello')

interfave Inter{
	length: number
}

//T extends Inter 表示泛型T必须是Inter实现类(子类)
function fn3<T extends Inter>(a: T):number{
	return a.length
}

//泛型类
class MyClass<T>{
	name: T;
	constructor(name:T){
		this.name = name;
	}
}

const mc = new MyClass<string>{name:'孙悟空'}

泛型在 TS 中可以说是一个非常重要的属性,它承载了从静态定义到动态调用的桥梁,同时也是 TS 对自己类型定义的元编程。泛型可以说是 TS 类型工具的精髓所在

一 . 基本使用

分普通类型定义,类定义,函数定义

// 普通类型定义
type Dog<T> = { name: string, type: T}

// 普通类型使用
const dog: Dog<number> = { name:'ww', type:20}

// 类定义
class Cat<T> = {
	private type:T,
	constructor(type:T){this.type = type}
}

// 类使用
const cat:Cat<number> = new Cat<number>(20) //或简写 const cat = new Cat(20)

// 函数定义
function swipe<T,U>(value:[T,U]):[U,T]{
	return [value[1],value[2]];
}

// 函数使用
swipe<Cat<number>,Dog<number>>([cat,dog])   // 或简写 swipe([cat, dog])

注意,如果对一个类型名定义了泛型,那么使用此类型名的时候一定要把泛型类型也写上去。

而对于变量来说,它的类型可以在调用时推断出来的话,就可以省略泛型书写。

泛型的语法格式简单总结如下:

类型名<泛型列表> 具体类型定义
二. 泛型推导与默认值

我们可以简化对泛型类型定义的书写,因为TS会自动根据变量定义时的类型推导出变量类型,这一般是发生在函数调用的场合的。

type Dog<T> = { name: string, type: T }

function adopt<T>(dog: Dog<T>) { return dog };

const dog = { name: 'ww', type: 'hsq' };  // 这里按照Dog类型的定义一个type为string的对象
adopt(dog);  // Pass: 函数会根据入参类型推断出type为string

若不适用函数泛型推导,我们若需要定义变量类型则必须指定泛型类型。

const dog: Dog<string> = { name: 'ww', type: 'hsq' }  // 不可省略<string>这部分

如果我们想不指定,可以使用泛型默认值的方案。

type Dog<T = any> = { name: string, type: T }
const dog: Dog = { name: 'ww', type: 'hsq' }
dog.type = 123;    // 不过这样type类型就是any了,无法自动推导出来,失去了泛型的意义

泛型默认值的语法格式简单总结如下:

泛型名 = 默认类型
泛型约束

有的时候,我们可以不用关注泛型具体的类型,如:

function fill<T>(length: number, value: T): T[]{
	return new Array(length).fill(value)
}

这个函数接受一个长度参数和默认值,结果就是生成使用默认值填充好对应个数的数组。我们不用对传入的参数做判断,直接填充就行了,但是有时候,我们需要限定类型,这时候使用extends关键字即可。

function sum<T extends number>(value: T[]):number{
	let count = 0
	value.forEach(v => count += v)
	return count
}

这样你就可以以sum([1,2,3])这种方式调用求和函数,而像sum([‘1’, ‘2’])这种是无法通过编译的。

泛型约束也可以用在多个泛型参数的情况。

function pick<T, U extends keyof T>(){}

这里的意思是限制了 U 一定是 T 的 key 类型中的子集,这种用法常常出现在一些泛型工具库中。

extends 的语法格式简单总结如下,注意下面的类型既可以是一般意义上的类型也可以是泛型。

泛型名 extends 类型
泛型条件

上面提到 extends,其实也可以当做一个三元运算符,如下:

T extends U? X: Y

这里便不限制 T 一定要是 U 的子类型,如果是 U 子类型,则将 T 定义为 X 类型,否则定义为 Y 类型。分配式结果

所以,extends 的语法格式可以扩展为

泛型名A extends 类型B ? 类型C: 类型D
泛型推断 infer

infer 的中文是“推断”的意思,一般是搭配上面的泛型条件语句使用的,所谓推断,就是你不用预先指定在泛型列表中,在运行时会自动判断,不过你得先预定义好整体的结构。举个例子

type Foo<T> = T extends {t: infer Test} ? Test: string

首先看extends后的内容,{t: infer Test}可以看成是一个包含t属性的类型定义,这个t属性的value类型通过infer进行推断后会赋值给Test类型,如果泛型实际参数符合{t: infer Test}的定义那么返回的就是Test类型,否则默认给缺省的string类型。

举个例子加深下理解:

type One = Foo<number>  // string,因为number不是一个包含t的对象类型
type Two = Foo<{t: boolean}>  // boolean,因为泛型参数匹配上了,使用了infer对应的type
type Three = Foo<{a: number, t: () => void}> // () => void,泛型定义是参数的子集,同样适配

infer用来对满足的泛型类型进行子类型的抽取,有很多高级的泛型工具也巧妙的使用了这个方法。

泛型 - 原文链接

【区分】 ts中的type 与 interface

一份不可多得的 TS 学习指南(1.8W字)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值