TS的各种操作

1,056 阅读6分钟
  • JS高级

怎么用?

下载

```js
npm install -g typescript
tsc -V
```

如何编译成js

  • 方法1: 手动编译 tsc hello.ts
  • 方法2:
    • VScode监视配置文件自动编译tsc --init
    • 生成tsconfig.json文件
    • 添加outDir
    • vscode顶部工具栏->终端->运行任务->tsc:监视tsconfig.json
  • 方法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类型可以用哪些方法 image.png

使用定义的接口,可以知道对象有哪些属性,方便进行补全代码

3. 提前预防代码错误

let isObj = a && b 

4. 实现面向对象的功能

声明文件:已有项目如何引入ts

  • 一些第三方库比如jQuery并不是使用TS写的, ts编译的时候会报错 JQuery("#id");

image.png

  • 兼容ts方法:需要使用declare声明jQuery的定义、告诉TS不要报错
declare const JQuery: (selector: string) => any;
// 这样不报错了,这样仅仅只是有了一个函数定义,并没有什么功能。
JQuery("#id");

image.png

  • 通常情况下,是把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文件 image.png

关闭.d.ts文件:报错了;因为ts默认读取的是node_modules下的@types库下的.d.ts文件 image.png 可以新建@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 ; 

案例

  1. webpack引入相关库的d.ts声明文件
  • react项目如何使用ts开发
    • 官网: www.html.cn/create-reac…
      1. 创建一个react+ts项目 $ npx create-react-app my-app --typescript
      1. 将ts添加到react项目中 npm install --save typescript @types/node @types/react @types/react-dom @types/jest
      1. 将任何文件重命名为 TypeScript 文件 (例如 src/index.js 重命名为 src/index.tsx )并 重新启动开发服务器!
  1. vue项目如何引入ts开发

    • 使用vue脚手架3或者4, 并选择手动指定配置,因为目前不支持
    • 使用VuePress搭建在线文档网站 -= vuepress.vuejs.org/zh/
  2. 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定义接口
  1. 接口定义对象类型
interface Item = {
    id: number;
    name: string;
    type?: string;
}
  • ducking typing(只要一个动物看能像鸭子一样游泳,有鸭子一样的特性,就可以被看成是鸭子)
 interface Item = {
    id: number;
    name: string;
    type?: string;
    // ducking  typing,鸭子类型,只要定了符合以下类型类型的,就可以看做是Item的属性
    [props:string]:any
}
  1. 给函数定义接口,也是可以的
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;
}
  1. 接口继承: **extends关键字 **
interface A extends B,C{}

案例

import { FormComponentProps } from 'antd/lib/form';
export interface CustomFromProps extends FormComponentProps {
  /**
   * 表单值改变
   */
  onChange?: Function;
  /**
   * 字段状态改变
   */
  onFieldsChange?: Function;
  /**
   * 表单的值
   */
  value?: any;
  1. 接口截取:定义了接口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 = () => {};
};

image.png

函数

function-type-expressions

  • 在使用过程中定义
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",
};