- JS高级
怎么用?
下载
```js
npm install -g typescript
tsc -V
```
如何编译成js
- 方法1: 手动编译
tsc hello.ts - 方法2:
- VScode监视配置文件自动编译
tsc --init - 生成
tsconfig.json文件 - 添加
outDir - vscode顶部工具栏->终端->运行任务->tsc:监视tsconfig.json
- VScode监视配置文件自动编译
- 方法3: webpack编译
- 配置
webpack.config.js typescript webpack webpack-cli webpack-dev-server html-webpack-plugin clean-webpack-plugin - ts-loader cross-env
- 配置
- 入口文件引入ts文件,webpack自动打包ts文件
ts作用
1. 变量数据类型的约束
如果定义了let a:string则a只能是string类型,如果赋值a为其他类型,会报错。
2. 变量对应方法的提示,协助补全属性
如果定义变量a为string类型,则ts会在使用a时,会提示string类型可以用哪些方法
使用定义的接口,可以知道对象有哪些属性,方便进行补全代码
3. 提前预防代码错误
let isObj = a && b
4. 实现面向对象的功能
声明文件:已有项目如何引入ts
- 一些第三方库比如jQuery并不是使用TS写的, ts编译的时候会报错
JQuery("#id");
- 兼容ts方法:需要使用
declare声明jQuery的定义、告诉TS不要报错
declare const JQuery: (selector: string) => any;
// 这样不报错了,这样仅仅只是有了一个函数定义,并没有什么功能。
JQuery("#id");
- 通常情况下,是把
declare定义单独放在.d.ts文件中 - 一般官方都有写好的定义,可以直接下载第三方库的声明文件
- 下载链接参考: 下载官方定义 如果只是下载定义,但是没有下载js文件,是无法使用第三库提供的功能的。
自己写一个声明文件
//fetch.ts
interface ResInteface {
name: string;
}
myFetch<ResInteface>("test", "GET", {}).then((res) => {
console.log(res);
});
myFetch.post<number>("test.com", {}).then((data) => {
console.log(data);
});
//test.d.ts
type MethodTypes = "POST" | "GET";
declare function myFetch<T = any>(
url: string,
method: MethodTypes,
params?: any
): Promise<T>;
// 定义变量上方法,如何定义myFetch上的方法
declare namespace myFetch {
const get: <T = any>(url: string) => Promise<T>;
const post: <T = any>(url: string, data: object) => Promise<T>;
}
同时同级的两个文件时,正常可以默认读到.d.ts文件
关闭.d.ts文件:报错了;因为ts默认读取的是node_modules下的@types库下的.d.ts文件
可以新建@types/myFetch文件夹,并导出该模块,之后在项目中引入
type MethodTypes = "POST" | "GET";
declare function myFetch<T = any>(
url: string,
method: MethodTypes,
params?: any
): Promise<T>;
// 定义变量上方法,如何定义myFetch上的方法
declare namespace myFetch {
const get: <T = any>(url: string) => Promise<T>;
const post: <T = any>(url: string, data: object) => Promise<T>;
}
// ts自创的模块导出
exports = myFetch ;
案例
- webpack引入相关库的d.ts声明文件
- react项目如何使用ts开发
- 官网: www.html.cn/create-reac…
-
- 创建一个react+ts项目
$ npx create-react-app my-app --typescript
- 创建一个react+ts项目
-
- 将ts添加到react项目中
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
- 将ts添加到react项目中
-
- 将任何文件重命名为 TypeScript 文件
(例如 src/index.js 重命名为 src/index.tsx )并 重新启动开发服务器!
- 将任何文件重命名为 TypeScript 文件
-
vue项目如何引入ts开发
- 使用vue脚手架3或者4, 并选择手动指定配置,因为目前不支持
- 使用VuePress搭建在线文档网站 -= vuepress.vuejs.org/zh/
-
d.ts声明文件
- 当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
- 声明语句: 如果需要ts对新的语法进行检查, 需要要加载了对应的类型说明代码
declare var jQuery: (selector: string) => any;
声明文件: 把声明语句放到一个单独的文件(jQuery.d.ts)中, ts会自动解析到项目中所有声明文件
下载声明文件 npm install @types/jquery --save-dev
有了这个声明文件才能使用这个库相关的语法提示
console.log($(‘body’))
ts数据类型
ts基础数据类型
- number
- string
- boolean
- null
- undefined
- array
- let arr1: number[]
- let arr2: Array
- tuple(元祖)
- 约束数组的类型和长度
let arr: [string,number]
type 类型别名:定义接口
type SumType = (x: number, y: number) => {};
const sum: SumType = (x, y) => {
return x + y;
};
sum(1, 3);
接口: inteface
- 接口: 约束对象的类型,接口是对象属性和方法的描述
- 定义方法:interface定义接口
- 接口定义对象类型
interface Item = {
id: number;
name: string;
type?: string;
}
- ducking typing(只要一个动物看能像鸭子一样游泳,有鸭子一样的特性,就可以被看成是鸭子)
interface Item = {
id: number;
name: string;
type?: string;
// ducking typing,鸭子类型,只要定了符合以下类型类型的,就可以看做是Item的属性
[props:string]:any
}
- 给函数定义接口,也是可以的
interface FunctionIter {
(x: number, y: number): number;
name: string;
}
const a = (x: number, y: number) => {
return x + y;
};
a.name = "a";
给个react定义函数接口的例子:React.FunctionComponent
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
- 接口继承: **extends关键字 **
interface A extends B,C{}
案例
import { FormComponentProps } from 'antd/lib/form';
export interface CustomFromProps extends FormComponentProps {
/**
* 表单值改变
*/
onChange?: Function;
/**
* 字段状态改变
*/
onFieldsChange?: Function;
/**
* 表单的值
*/
value?: any;
- 接口截取:定义了接口A,想约束对象Obj为接口A中其中一项的数据类型。 抽取常量,高阶写法(案例,多tab页面,一个code对应一个类型)
//定义
export const DURATION_TYPE = "DURATION";
export const SHELF_TYPE = "SHELF";
export DURATION_CODE = "1001";
export SHELF_CODE = "1002";
export const TAB_STYLE: {[props:string]: string} = {
[DURATION_CODE]: DURATION_TYPE,
[SHELF_CODE]: SHELF_TYPE,
}
//使用
import {TAB_STYLE,DURATION_TYPE,SHELF_TYPE,DURATION_CODE,SHELF_CODE} from "../type";
const tabCode = "1001"; //模拟数据
if(TAB_STYLE[tabCode] === DURATION_TYPE){
// 如果是样式A
}else{
// 如果是样式B
}
class的约束
类的定义
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
run = () => {
return `${this.name}`;
};
}
const snake = new Animal("snake");
snake.run();
类的继承
class Dog extends Animal {
swimming = () => {
console.log(`${this.name} is swimming`);
};
}
const dog = new Dog("dog");
dog.swimming();
dog.run();
重写: 子类重写父类方法
类的多态
- 父类型引用指向子类型的实例 ===> 多态
- 子类型引用指向父类型实例 ===>子类型没有新的方法才可以
类对应的TS约束
类属性的修饰符
- public 公共的
- private 私有的,外面属性方法不可见
- protected 类型,子类以外不可见
- readonly 只能读不能改
- static 类的静态属性 类本身的属性而不是实例对象上的
类的存取器
- get set
抽象类
- abstract关键字
- 不能被实例化
- 抽象类必须包含抽象方法,
- 只能子类继承并实现该抽象方法
类分为两种类型
实例类型的约束
implements关键字:方便逻辑功能的提取并且分别进行约束
- 描述:类遵循接口的约束
interface Clock {
currentTime: number;
clock: Function;
}
interface GameInterface {
play: Function
}
class CellPhone implements Clock,GameInterface {
currentTime:number = 123
clock = ()=>{};
play = ()={}
}
案例:对业务类型的提取
// 该interface不能约束类的构造函数
interface Clock {
currentTime: number;
clock: Function;
}
interface GameInterface {
play(): void;
}
class CellPhone implements Clock, GameInterface {
currentTime: number = 123;
clock = () => {};
play = () => {};
}
静态类型
可以约束类的构造函数和静态属性
interface Clock {
currentTime: number;
clock: Function;
}
interface GameInterface {
play(): void;
}
interface CellPhoneStatic {
new (h: number, m: number): void; //约束类的构造函数
time: number; //约束类的静态方法
}
const Cellphone: CellPhoneStatic = class CellPhone
implements Clock, GameInterface
{
constructor(h: number, m: number) {}
static time = 12;
currentTime: number = 123;
clock = () => {};
play = () => {};
};
函数
- 在使用过程中定义
function greeter(fn: (a: string) => void) {
fn("Hello, World");
}
function printToConsole(s: string) {
console.log(s);
}
greeter(printToConsole);
-
使用类型别名定义:
type GreetFunction = (a: string) => void;- a为入参,void为返参的类型
-
如果入参和返参类型有关联,或两个入参之间有对应关系,则使用
泛型定义
通过向Type这个函数添加一个类型参数并在两个地方使用它,我们在函数的输入(数组)和输出(返回值)之间创建了一个链接。现在当我们调用它时,会出现一个更具体的类型:
调用的时候也不需要指定泛型类型,ts自己来推断。
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0];
}
// s is of type 'string'
const s = firstElement(["a", "b", "c"]);
// n is of type 'number'
const n = firstElement([1, 2, 3]);
// u is of type undefined
const u = firstElement([]);
- const定义函数,结合泛型
export const getObjectKeys = <T>(obj: T) => Object.keys(obj) as (keyof T)[];
ts内置对象
- ECMAScript 的内置对象
- Boolean
- Number
- String
- Date
- RegExp
- Error
- BOM 和 DOM 的内置对象
- Window
- Document
- HTMLElement
- DocumentFragment
- Event
- NodeList
- Promise
遇到的一些ts的问题
将类型T中的某个或某些类型变为可选
interface FetchParams {
readonly prodSupplier: string;
readonly userProdId: string;
readonly subSupplier: string;
orderStatus: "processing" | null | undefined;
pageNo: number;
pageSize: number;
orderType: "01" | "17";
}
type OptionalType<T, K extends keyof T> = {
[P in K]?: T[P]; // K可以是单个类型,也可以是联合类型
} & Omit<T, K>;
const fetchBaseArgs = {
prodSupplier: "122",
userProdId: "1222",
subSupplier: "222",
orderStatus: null,
pageNo: 1,
pageSize: 20,
};
const fetchArgs: OptionalType<FetchParams, "orderType"> = {
...fetchBaseArgs,
};
从T中提取部分类型,在加上一些类型
/**
* 从T中提取部分类型,在加上一些类型
* 也就是从类型T中删除部分类型,再加上一些其他类型
*/
type OptionalTypeP<T, K extends keyof T> = Omit<T, K> & {
time: string;
data: object;
};
// 去除类型FetchParams中的"pageNo" | "pageSize",在此基础上加上类型time和data类型
const res: OptionalTypeP<FetchParams, "pageNo" | "pageSize"> = {
time: "2020-10",
data: {},
prodSupplier: "122",
userProdId: "1222",
subSupplier: "222",
orderStatus: null,
orderType: "01",
};