// 函数泛型
function setParamsType<T>(arg: T): T {
return arg;
}
console.log(setParamsType<string>('maic'));
console.log(setParamsType<number>(18));
与下面等价,可以用interface申明函数类型
// 接口泛型
interface paramsType<T> {
[arg: T]: T;
}
function setParamsType<T>(arg: T): T {
return arg;
}
const myParams: parsType<number> = setParamsType;
// type 泛型
type parsType2<T> = {
[arg: T]: T;
};
const myParams2: parsType2<number> = setParamsType;
类泛型
我们在用class申明类时,就可以约定类中成员属性的类型以及class内部方法返回的类型
class Calculate<T> {
initNum: T;
max: string;
add: (x: T, y: T) => T;
}
const cal = new Calculate<number>();
cal.initNum = 0;
cal.add = (x, y) => x + y;
cal.add(1, 2);
// or
const cal2 = new Calculate<string>();
cal.max = '123';
cal.add = (x, y) => x + y;
cal.add(cal.max, '456'); // 123456
约束泛型
在平时项目中我们使用泛型,我们会发现有时候,函数内部使用参数时,往往会提示属性不存在,比如
// 类型“T”上不存在属性“id”。
function getParams<T>(params: T) {
if (params.id) {
console.log('进行xxx操作');
}
}
getParams({ id: '123' });
此时我们就可以利用extends约束泛型做到函数内部能正确访问
function getParams<T extends { id: string }>(params: T) {
if (params.id) {
console.log('进行xxx操作');
}
}
getParams({ id: '123' });
interface parmasType {
id: string;
}
function getParams2<T extends parmasType>(params: T) {
if (params.id) {
console.log('进行xxx操作');
}
}
接下来看一段原型属性推断与约束,我们可以看出构造函数与实例的关系
class Animal2 {
name: string = 'animal';
}
class Sleep {
hour: number = 10;
}
class Bee extends Animal2 {
age: number = 1;
action: Sleep = new Sleep();
}
function createInstance<T extends Animal2>(c: new () => T): T {
return new c();
}
console.log(createInstance(Bee).action.hour); // animal
function fnTest() {
return {
a: '111',
b: '222'
};
}
type fntest = ReturnType<typeof fnTest>;
/**
type fntest = {
a: string;
b: string;
}
**/
我们可以看下ReturnType的类型定义
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
有时候我们定义一个枚举,我们想获取枚举的Key,那么可以这么做
enum SERVER {
TEST = 1,
PRD = 2,
DEV = 3
}
type serverType = keyof typeof SERVER;
// type serverType = "TEST" | "PRD" | "DEV"
访问索引类型
有时我们需要访问具体接口的某个字段的类型或者数组中的类型
interface person {
name: string;
id: number;
age: number;
}
type nametype = person['age'];
// type nametype = number
type nameOrAge = person['age' | 'name'];
// type nameOrAge = string | number
type personKeys = person[keyof person];
// type personKeys = string | number
最近半年项目升级 ts,一边看文档,一边实践,
ts
基础语法非常简单,但是写好ts
就非常不简单,typescript
严格来讲算是一门强类型语言,它赋予js
类型体系,让开发者写js
更加严谨,并且它具备强大的类型推断,并且能在node
和浏览器
中运行。对于项目而言,使用 typescipt 对提升项目的规范与严谨性更加友好。本文只做笔者项目中常遇到的一些
ts
经验,希望在项目中你能用得到。正文开始...
定义常用类型
type
[string|number|boolean|Array|Object|Function]
定义数组对象的类型
类型推断和提示
定义对象类型
定义函数类型
函数形参类型
注意以上第二个形参中
?age:number
代表这个形参可传可不传,并且这个函数返回的值类型是一个字符串
联合类型[string[] | number]
toString
这个方法在数组和number
中都有该方法,所以可以使用,如果某个方法只存在于一种类型中,则要类型收窄
判断该类型interface 接口
interface
我们可以理解它是定义对象的一种类型,并且它具备扩展
对象属性,继承对象特征 在之前我们用type
定义了对象数据用
interface
定义对象如果我需要一个对象类型的属性是
可选的
只需要在定义的属性后面加个
?
就行extends 继承并扩展属性
type
通过交集扩展属性这里我们注意比较下
type
与interfance
的区别相同点
所有对象类型都可以用
type
或者interface
来定义,type
在实际项目中更广义些,而interface
更多的时候描述一个对象类型更狭义一些,他们都可以定义对象类型不同点
type
定义好了的数据,不能重载,且扩展属性需要使用交集扩展&
interface
可以重载,扩展属性需使用extends
as 类型断言
在项目中,如果你不知道该形参或者变量的类型,如果只是为了快点糊项目,不想被这个类型所拘束,那么你可以用
as any
联合类型
in 收窄类型
将一个的
enums
值的value
做为另一个对象的key
,将一个枚举值的key
作为一个对象的value
instanceof 收窄
我们可以用
instanceof
收窄数据类型is 判断
我么判断一个形参是否在一个类型中
rest params
可以跟
es6
一样...
扩展多个参数可选属性[?]or 只读属性[readonly]
我们想一个对象的属性可有可无,或者一个对象属性不能修改
对象索引类型
通常我们一个对象的
key
是字符串或者是索引,那么正确定义对象索引的类型就如下面如果我需要将一个对象
key
声明成另一个对象的key
呢?那么我们可以使用[key in xxx]: string
交叉类型 x & b
注意我们使用
extends
也一样可以一样的效果利用泛型复用 interface
通常在实际业务中, 通用的属性值可能类型不同那么我们会重复定义很多类型,比如下面
因此我们可以这么做
当我们看到
interface objType<T> { a: T }
,我们怎么理解,首先objType
你可以把它看成一个接口名称,其实与普通申明一个普通接口名
一样,T
可以看成一个形参,一个占位符,我们可以在实际用的地方灵活的传入不同类型。type 泛型复用
方法泛型复用
通常我们在项目中经常看到封装的工具函数中有泛型,那么我们可以简单的写个,具体可以看下下面简单的一个一个工具请求函数
readOnly 只读
[xx,xx,xx] as const
内部元素会变成一个常量,不可修改
泛型
对于
泛型
在笔者初次遇见她时,还是相当陌生的,感觉这词很抽象,不好理解,光看别人写的,一堆泛型,或许增加了阅读代码的复杂度,但是泛型用好了,那么会极大的增加代码的复用度。当然,简单事情复杂化了,那么泛型也容易出错,代码也变得不易读。我们写一个简单的例子来感受一下泛型
如果我想
resopnseID
或者responseName
高度复用呢,如果有很多类似的字段,那么我是不是要写很多这种接口类型呢与下面等价,可以用
interface
申明函数类型类泛型
我们在用
class
申明类时,就可以约定类中成员属性的类型以及class
内部方法返回的类型约束泛型
在平时项目中我们使用泛型,我们会发现有时候,函数内部使用参数时,往往会提示属性不存在,比如
此时我们就可以利用
extends
约束泛型做到函数内部能正确访问接下来看一段原型属性推断与约束,我们可以看出构造函数与实例的关系
keyof
我们对一个对象类型接口进行
keyof
那么会返回对象属名组成的集合如何获取一个对象值的所有
key
通过
keyof
我们已经约束了一新值的所有值,那么它就再也不能赋值其他值了,比如Extract
当我们对一个对一个泛型进行
keyof
时,此时类型会变成string | number | symbol
三种类型,我们对变量进行赋值时,ts
会报错那么此时我们需要借助
Extract
进一步进行约束注意我们看下
ts
全局给我们提供的这个Extract
类型我们观察到
Extract
就是约束了Key
的类型,那么我们也可以这么写,既然我知道Key
是字符串或者你也可以用或类型,指定
keyName
可以是string | number | symbol
这三种类型typeof
typeof
只能用于已经实际定义申明了的变量,返回该定义的变量的实际类型但是注意如果用
const
定义的变量,如果你keyof
一个常量,那么就会不一样了获取一个
对象
的所有属性类型获取一个
函数
的返回类型,ReturnType
我们可以看下
ReturnType
的类型定义有时候我们定义一个枚举,我们想获取枚举的
Key
,那么可以这么做访问索引类型
有时我们需要访问具体接口的某个字段的类型或者数组中的类型
数组中的类型
条件类型 extends
此时可以用
extends
总结
1、在
ts
定义基础数据类型,type
与interface
2、基础使用泛型,可以在
接口
,函数
,type
使用泛型,泛型可以理解js
中的形参,更加抽象和组织代码3、
extends
约束泛型,并且可以在ts
中做条件判断4、使用
keyof
获取对象属性key
值,如果需要获取一个对象定义的key
,可以使用type keys = keyof typeof obj
5、有一篇笔者很早之前的一篇ts 笔记
6、本文示例code-example
更多学习
ts
查看TS 官方文档,也可以看对应翻译中文版https://yayujs.com/