前言: 本文章为 TypeScript 系列文章. 旨在利用碎片时间快速入门 Typescript. 或从新温故 Typescript 查漏补缺.在官方 api 的基础上, 加上一些平常使用的感想. 若是感兴趣的话~ 欢迎关注, 后续持续推出文章.javascript
文章列表:前端
目录结构:java
javascript 做为一门动态语言, 在实际运行的时候,等变量被赋值才知道该变量的类型. 动态语言给实际的编码带来了很大的灵活性.react
function getVal(val) {
retrurn val;
}
getVal(1) // 返回数字类型
getVal('1') // 返回字符串类型
getVal(['2']) // 返回数组类型
复制代码
可是一样的, 在代码运行期间有可能会发生与类型相关的错误, 下降了代码的可维护性. 那下面咱们用 typescript 来定义变量. 为了支持3种调用方式, 咱们须要声明三种类型定义. 有2种方法能够解决上面这个问题.程序员
function getVal(val: number): number
function getVal(val: string):string
function getVal(val: any):any {
return val;
}
复制代码
function getVal(val: string | number | any[]):string | number | any[] {
return val;
}
复制代码
做为一个程序员, 上面2种方法让咱们感觉重复繁琐. 这是没法容忍的. 那怎么样可让该函数又能够在运行的时候被赋值才肯定该变量的类型, 又有必定的类型约束减小相关的错误? 答案就是: 泛型ajax
function getVal<T>(val: T): T {
return val;
}
复制代码
T 即表明捕获函数传入的参数类型, 而后在函数内部使用 T 即用该参数类型声明其余变量. 可是咱们从上面的函数看出, 由于 T 是捕获参数传入的参数类型,typescript
而这个函数能够传入任意参数, 与咱们最开始只支持3个类型的需求不符. 因此下面要引入泛型约束.api
type Params= string | number | any[];
function getVal<T extends Params>(val: T): T {
return val;
}
getVal(1);
getVal('2');
getVal(['222']);
getVal<number>('3'); // 跟泛型指定的类型不一致, 报错
getVal({}); // 不是 Param 类型, 报错
复制代码
泛型便可以声明函数, 也能够声明类. 也能够声明接口数组
class Person<T>{} // 一个尖括号跟在类名后面
function Person<T> {} // 一个尖括号跟在函数名后面
interface Person<T> {} // 一个尖括号跟在接口名后面
复制代码
有些时候, 一个类或者一个函数里面, 他不止要用到一个动态类型, 他要用到多个. 可是咱们上面只能捕获一个, 那直接声明多个不就行了?bash
function getName<T,U> (name: T, id: U): [T, U] {
return [name, id]
}
getName('peen', 1);
getName('peen', '222'); // 正常
getName<string, number>('peen', '22'); // 报错: '22'不是number类型
复制代码
在实际项目中, 每一个项目都须要接口请求, 咱们会封装一个通用的接口请求, 在这个函数里面, 处理一些常见的错误等等. 为了让每一个接口调用都有 typescript 约束, 提醒. 这里使用泛型是很是合适了.
interface IApiSourceParams {
GetList: IGetList
}
interface IGetList {
id: number;
}
export function fetchApi<T extends keyof IApiSourceParams>(action: T, params: IApiSourceParams[T]) {
return ajax({
url: action,
method: 'POST',
body: params
})
}
fetchApi('GetList', { id: 2 });
fetchApi('GetList', { id: '33' }); // 报错, id 应该是 number 类型
复制代码
这样子, 咱们就给一个通用的接口请求函数增长了类型约束. 在 IApiSourceParams 中扩展每个接口类型便可.
从上面的例子看到了 T extends keyof IApiSourceParams , 这在上文中没有看到. 实际这种应用场景特别多.
索引类型查询操做符: keyof , 对于任何类型 T, keyof T的结果为 T上已知的公共属性名的联合. 看着话有点绕, 直接看例子吧
interface Person {
name: string;
age: number;
}
let personProps: keyof Person; // 'name' | 'age'
复制代码
索引访问操做符 : T[K] . 上面的 keyof 实际就是获取了对象的键值, 看一下上面的实际例子
interface IApiSourceParams {
GetList: IGetList,
PostApi: IPostApi
}
interface IGetList {
id: number;
}
export function fetchApi<T extends keyof IApiSourceParams>(action: T, params: IApiSourceParams[T]) {
return ajax({
url: action,
method: 'POST',
body: params
})
}
// IApiSourceParams[T] 获取的即是接口 IApiSourceParams 对应key值的接口 IGetList.
复制代码
泛型在各大库中都很是普遍的使用, 下面选react中的类和react hook 实地分析
1、react 类
若是使用过 react , 确定见过下面这种语法声明 props 和 state
class Test extends Component<IProps, IState> {}
复制代码
咱们再看看 react class 里面的 typescript 声明
class Component<P, S> {
static contextType?: Context<any>;
context: any;
constructor(props: Readonly<P>);
constructor(props: P, context?: any);
setState<K extends keyof S>(
state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null),
callback?: () => void
): void;
forceUpdate(callBack?: () => void): void;
render(): ReactNode;
readonly props: Readonly<P> & Readonly<{ children?: ReactNode }>;
state: Readonly<S>;
refs: {
[key: string]: ReactInstance
};
}
复制代码
能够看到react以及提早帮忙作好了一些约束
2、React HOOK
咱们随便找一个最常使用的 useState 方法.
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
复制代码
因此咱们在使用的时候, 能够
const [errorMessage, setError] = useState<string>('');
复制代码
本篇文章讲了泛型解决的场景以及语法. 并介绍了一些实际的应用场景. 最后欢迎关注「前端加加」,认真学前端,作个有专业的技术人...