目录
- Typescrip异步函数Promise
- typescript- typescrip与react
- 对象的类型
- 数组类型
- 函数类型
- 类型断言
- 内置对象
- 泛型
- React 中使用
Typescrip异步函数Promise
var p = new Promise(function (resolve, reject) {
var x = 1;
if (x > 0) {
resolve({ msg: '异步调用成功', data: { x: 1, y: 2 } });
}
else {
reject({ msg: '异步调用失败', data: {} });
}
});
//异步调用结果
p.then(function (data) {
console.log('OK');
console.log(data);
//console.log(data.msg,data.data);
})["catch"](function (err) {
console.log(err);
});
//异步函数
function promiseFunc(t) {
console.log("".concat(t / 1000, "\u79D2\u540E\u8C03\u7528\u5F02\u6B65"));
return new Promise(function (resolve, reject) {
setTimeout(resolve, t, '异步调用完成');
});
}
//调用异步函数
promiseFunc(1000).then(function (value) { console.log(value); });
var promiseAction = new Promise(function (resolve, reject) {
console.log('执行了一些异步操作...');
resolve('异步操作完成了!');
});
promiseAction.then(function (value) { console.log(value); });
// @ts-ignore
// const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
// let getDataAsync=(url)=>{
// let p = new Promise((resolve, reject) => {
// let c =new XMLHttpRequest();
// c.open('GET',url);
// c.onreadystatechange = h;
// c.responseType = 'json';
// c.setRequestHeader('Accept','application/json');
// c.send();
// function h(){
// if(this.readyState!==4){return;}
// if (this.status===200){
// console.log('请求成功返回:',this.status);
// resolve(this.response);
// }else {
// reject(new Error(this.statusText));
// }
// }
// });
// return p;
// };
// getDataAsync('http://192.168.31.180/data.json')
// .then(data=>{console.log(data);})
// .catch(err=>{console.log(err);});
//通过https加载json数据
var url = 'https://img-home.csdnimg.cn/data_json/toolbar/toolbar1105.json';
var url1 = 'https://mp-api.iqiyi.com/base/api/1.0/get_role';
var GetJsonData = function (url) {
var https = require('https');
https.get(url, function (response) {
var data = '';
//数据正在接收中...
response.on('data', function (chunk) {
data += chunk;
});
//数据接收完成
response.on('end', function () {
console.log('同步请求数据完成:', JSON.parse(data));
});
}).on("error", function (error) {
console.log("Error: " + error.message);
});
};
GetJsonData(url);
//异步请求JSON数据实现
var GetJsonDataAsync = function (url) {
var https = require('https');
return new Promise(function (resolve, reject) {
https.get(url, function (response) {
var data = '';
//数据正在接收中...
response.on('data', function (chunk) {
data += chunk;
});
//数据接收完成
response.on('end', function () {
//console.log(JSON.parse(data));
resolve(data); //数据接收完成
});
}).on("error", function (error) {
console.log("Error: " + error.message);
reject(new Error(error.message));
});
});
};
//异步调用
GetJsonDataAsync(url).then(function (value) {
console.log("======================下面为异步加载数据=================================");
if (typeof value === "string") {
console.log('异步加载请求数据完成:', JSON.parse(value));
}
})["catch"](function (err) { console.log(err); });
//通过request库请求json数据,使用前 sudo npm i -g request安装包
var request = require('request');
request(url, function (error, response, body) {
console.error('错误:', error);
console.log('状态码:', response && response.statusCode);
console.log('数据:', JSON.parse(body));
});
//异步方式
var RequestJsonAsync = function (url) {
return new Promise(function (resolve, reject) {
request(url, function (e, r, d) {
if (null != e) {
reject(new Error(e));
}
else {
resolve(JSON.parse(d));
}
});
});
};
RequestJsonAsync(url).then(function (value) {
console.log("==============request异步加载json===============================");
console.log(value);
})["catch"](function (err) { console.log(err); });
//nodejs needle库使用 ,使用前 npm i needle --save 安装包
var needle = require('needle');
needle.get(url, function (error, response) {
if (!error && response.statusCode == 200)
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", response.body);
});
//异步模式
needle('get', url, { json: true }).then(function (resp) {
if (resp.statusCode == 200) {
console.log(">>>>>>>>>>>>>>异步模式>>>>>>>>>>>>>>>>>>>>>>>>>>>>>", resp.body);
}
})["catch"](function (err) { console.log(err); });
//使用axios库使用,axios直接异步 使用前安装 npm i -g axios --save
var axios = require('axios');
axios.get(url)
.then(function (res) {
console.log(res);
})["catch"](function (err) {
console.log(err);
});
//axios支持多请求并发
axios.all([
axios.get(url),
axios.get(url1)
]).then(axios.spread(function (res1, res2) {
console.log(res1);
console.log(res2);
}))["catch"](function (err) {
console.log(err);
});
//supertaget库使用
var superagent = require('superagent');
superagent.get(url)
.end(function (err, res) {
if (err) {
return console.log(err);
}
console.log("superagent库调用==========>", res.body);
});
//fetch库使用 使用前安装 npm i node-fetch 3x版本只能import导入 --save 支持异步
// @ts-ignore
// import fetch from 'node-fetch'; //不能在模块之外使用
// fetch(url)
// .then(res => res.json()) // expecting a json response
// .then(json => {
// console.log(json);
// })
// .catch(err => {
// console.log(err);
// });
var p1 = new Promise(function (resolve, reject) {
resolve('p1 resolve');
});
var p2 = new Promise(function (resolve, reject) {
resolve('p2 resolve');
});
//只要p1,p2中的其中一个有状态改变,马上返回pRace
var pRace = Promise.race([p1, p2]);//将多个Promise生成一个Promise
pRace.then(function (value) {
console.log(value);
});
typescript- typescrip与react
对象的类型
接口 Interfaces 一般首字母大写
interface Person {
readonly id: number; // 只读属性 不能修改
name: string;
age: number;
age?: number; // 可选
[propName: string]: any; // 任意属性
// 注意,
}
// 顺序 一般是 只读 -> 默认 -> 可选 -> 任意
let tom: Person = {
name: 'Tom',
age: 25
};
一旦定义了任意属性,那么确定属性和可选属性的类型都必须是它的类型的子集:
interface Person {
name: string;
age?: number;
[propName: string]: string;
}
let tom: Person = {
name: 'Tom',
age: 25, // 报错 需要是 任意属性的子集
gender: 'male'
};
任意属性的值允许是 string,但是可选属性 age 的值却是 number,number 不是 string 的子属性,所以报错了
只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
interface Person {
readonly id: number;
name: string;
age?: number;
[propName: string]: any;
}
let tom: Person = {
name: 'Tom',
gender: 'male'
};
tom.id = 89757; // 报错,第一处是在对 tom 进行赋值的时候,没有给 id 赋值。 之后再赋值就报错
数组类型
「类型 + 方括号」表示法
let arr: number[] = [1, 2, 3, 4, 5]; // 表示 是数组, 并且数组元素只能为 number 类型
联合类型和数组的结合
// arr 表示 是数组, 并且数组元素只能为 number 和 string 类型
let arr: (number | string)[] = ['1', 'adaf', 2, 3, 5]
数组泛型
let arr: Array<number> = [1, 2, 3, 4, 5];
类数组
常见的类数组都有自己的接口定义,如 IArguments, NodeList, HTMLCollection 等
// error 函数中的 arguments 这也定义会报错
let args: number[] = arguments;
// success 改成
let args: IArguments = arguments;
函数类型
函数声明
function sum(x: number, y: number): number {
return x + y;
}
函数表达式
let mySum = function (x: number, y: number): number {
return x + y;
};
这是可以通过编译的,不过事实上,上面的代码只对等号右侧的匿名函数进行了类型定义,而等号左边的 mySum,是通过赋值操作进行类型推论而推断出来的。如果需要我们手动给 mySum 添加类型,则应该是这样:
let mySum: (x: number, y: number) => number = function (x: number, y: number): number {
return x + y;
};
类型断言
function getLength(something: string | number): number {
// 将他断言为 string
if ((<string>something).length) {
return (<string>something).length;
} else {
return something.toString().length;
}
}
类型断言不是类型转换,断言成一个联合类型中不存在的类型是不允许的:
// error
function toBoolean(something: string | number): boolean {
return <boolean>something;
}
// Type 'number' is not comparable to type 'boolean'
内置对象
ECMAScript 的内置对象
Boolean、Error、Date、RegExp 等。
DOM 和 BOM 的内置对象
Document、HTMLElement、Event、NodeList 等。
泛型
是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
问题
type 和 Interfaces 的区别
React 中使用
import React, { MouseEvent, ReactNode } from 'react'
type Props = {
onClick(e: MouseEvent<HTMLElement>): void
children?: ReactNode
}
const Button = ({ onClick: handleClick, children }: Props) => (
<button onClick={handleClick}>{children}</button>
)
高阶组件的使用方式
import React from 'react';
import { Form } from 'antd';
import { FormComponentProps } from 'antd/es/form';
interface IProps extends FormComponentProps {
loading: boolean;
}
const Page: React.FC<IProps> = (props) => {
return (
<div>Page</div>
)
}
export default Form.create<IProps>()(Page)
对象类型取值
type DealWithProps = {
onClose: Function;
eventId: string;
dealTime: any;
};
// 处理
const getOnDealWith = (parameObj: DealWithProps) => () => {
// TODO 暂无接口
for (let i in parameObj) {
console.log(parameObj[i], typeof parameObj[i]);
// 报错
/**
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'DealWithProps'.
No index signature with a parameter of type 'string' was found on type 'DealWithProps'.ts(7053)
**/
}
};
Event 事件对象类型
常用 Event 事件对象类型:
ClipboardEvent<T = Element>
剪贴板事件对象DragEvent<T = Element>
拖拽事件对象ChangeEvent<T = Element>
Change 事件对象KeyboardEvent<T = Element>
键盘事件对象MouseEvent<T = Element>
鼠标事件对象TouchEvent<T = Element>
触摸事件对象WheelEvent<T = Element>
滚轮事件对象AnimationEvent<T = Element>
动画事件对象TransitionEvent<T = Element>
过渡事件对象
Promise 类型
Promise<T> 是一个泛型类型,T 泛型变量用于确定使用 then 方法时接收的第一个回调函数(onfulfilled)的参数类型。
interface IResponse<T> {
message: string,
result: T,
success: boolean,
}
async function getResponse (): Promise<IResponse<number[]>> {
return {
message: '获取成功',
result: [1, 2, 3],
success: true,
}
}
getResponse()
.then(response => {
console.log(response.result)
})
使用 react-router-dom
withRouter(ModuleLayout)
这类高阶组件的使用 方式,通常都需要继承到高阶组件 的 类型定义,如 antd Form.create 需要继承 FormComponentProps
import { FormComponentProps} from 'antd/lib/form/Form';
import { withRouter, Link, RouteComponentProps } from 'react-router-dom';
interface IProps extends RouteComponentProps<any> {
basePath: string;
menuList: IMenuItem[];
children: JSX.Element;
}
function App(props: IProps){
// 因为继承了 RouteComponentProps 所以可以获取 location
const {location} = props;
// xx
}
export default withRouter(ModuleLayout);
react 定义方法 useApi
/* eslint-disable no-param-reassign */
import { useRef, useEffect } from '@alipay/bigfish/react';
import { useImmer } from 'use-immer';
type Service<T> = () => Promise<T>;
type DependencyList = ReadonlyArray<any>;
interface Option<T> {
onSuccess?: (data: T) => void;
onError?: (errMsg: string) => void;
}
interface State {
data: any;
loading: boolean;
}
interface ResponseData<T> {
success: boolean;
data: T;
message: string;
}
export default function useApi<T>(
service: Service<ResponseData<T>>,
dependencyList: DependencyList = [],
option?: Option<T>
) {
const initialState: State = {
data: undefined,
loading: false,
};
const [state, setState] = useImmer(initialState);
const serviceId = useRef(0);
useEffect(() => {
const currentId = serviceId.current;
setState(draft => {
draft.loading = true;
draft.data = null;
});
// 异步方法
service().then(data => {
// 组件卸载不更改
if (currentId !== serviceId.current) {
return;
}
if (!data.success) {
// 错误
setState(draft => {
draft.loading = false;
draft.data = null;
});
if (option && option.onError) {
option.onError(data.message);
}
} else {
// 成功
setState(draft => {
draft.loading = false;
draft.data = data.data;
});
if (option && option.onSuccess) {
option.onSuccess(data.data);
}
}
});
return () => {
serviceId.current += 1;
};
}, dependencyList);
return [state, setState];
}
react 使用 useRef
import React, { useRef, useState, FC } from '@alipay/bigfish/react';
import { message } from 'antd';
interface IProps extends FormComponentProps {
isShow:boolean;
}
interface IUseRef extends HTMLDivElement {
getAssets: Function;
}
const CreateStep: FC<IProps> = props => {
const {
form, isShow
} = props;
const refList = useRef<IUseRef>(null);
const [current, setCurrent] = useState(1);
function setNextStep() {
const { current } = refList;
const { getAssets } = current; // 类型“IUseRef | null”上不存在属性“getAssets”
}
return <div ref={refList}>xxxx</div>;
};
export default CreateStep;
上面定义泛型的时候, 这个写法会报一个错误,因为 current 开始会是空的,后面 dom 挂在之后才会获取实例。
看下 useRef 源码定义, 也就是泛型的值就是 current 的结果
interface RefObject<T> {
readonly current: T | null;
}
function useRef<T>(initialValue: T|null): RefObject<T>;
并且 ref={ refLise } 需要传入的是 dom 元素节点,所以通过继承 HTMLDivElement 来得到 useRef 泛型。
interface IUseRef extends HTMLDivElement {
getAssets: Function;
}
所以解决的方法。
方法一: 类型断言, 但是这样的代码其实是不严警的
const { getAssets } = current as IUseRef;
方法二: 通过 if 判断,消除 current 为 null 的时候,如果不为 null 这里的类型就必定是 IUseRef 类型,所以可以取出 getAssets
let getAssets ;
if(current && current.getAssets){
getAssets = current.getAssets;
}