typescript常用总结

100 阅读9分钟

基本类型

  • string、number、boolean、undefined、null

赋值时自动判定类型,无需定义

let aa = '1'; 
// 等同于
let aa: string = '1';
  • 拓展的基础类型:any、void、never

any:任意类型,不确定类型或者类型是动态的

void:表示无任何类型,正好与 any 相反。对于变量,表示类型为 undefined 或 null;对于函数,表示函数没有返回值,或者返回 undefined

function aa(): void{
    console.log('无返回')
}

never:表示永远不存在值。一般用在抛出异常的函数

function aa(): never{
    throw new Error('报错')
}

unknown:表示未知类型。即写代码的时候还不清楚会得到怎样的数据类型,如服务器接口返回的数据,JSON.parse() 返回的结果等

它能被赋值为任何类型,但不能被赋值给除了 any 和 unknown 之外的其他类型,同时,不允许执行 unknown 类型变量的方法(any 可以)

let uk: unknown = 'abc';
uk = 123;
uk = true;
uk.toString(); // Error

let valAny: any = 'abc';
valAny.toString(); // 'abc'

let uk1: unknown = uk;
let uk2: any = uk;
let uk2: string = uk; // Error,只能赋值any 和 unknown类型

引用类型

  • 数组类型
let arr: string[] = ['a', 'b', 'c'];
// 等同于
let arr: Array<string> = ['a', 'b', 'c'];

// 只读数据
let arrR: ReadonlyArray<string> = ['a', 'b', 'c'];
arrR[0] = 'd'; // 报错
  • object: 表示类型为对象,除基本类型外的类型

函数类型

function aa(x: number, y: number): number {
    return x + y;
}
aa(1, 2);

枚举 enum

// 1、默认从 0 递增赋值
enum EColor {Red, Blue, Green};
console.log(EColor["Red"] === 0); // true
console.log(EColor["Blue"] === 1); // true

// 2、手动赋值
enum EDays {
    Mon = 'mon',
    TUE = 'tue',
    WEN = 'wen'
}
console.log(EDays["Mon"] === 0); // true

// 3、只允许输入EDays的值
function aa(day: EDays){
    console.log(day) // tue
}
aa(EDays.TUE)

// 4、可循环遍历
for(let item of Object.entries(Days)){
    console.log(item) // ["Mon", "mon"] ...等等
}

// 5、固定值
type name = 'tom' | 'cat';
const fullName: name = 'tom';  // 只能为'tom' | 'cat'

高级类型:联合类型、交叉类型、类型断言

  • 联合类型 可取多种类型,如:
// 基本类型
let aa: string | number;
aa = '1';
aa = 1;

// 数组
let arr: number[] | string[]; 
arr = [1, 2, 4] 
arr = ['a', 'b', 'c'] 

// 对象

interface IRectangle {
    kind: 'rectangle';
    width: number;
    height?: number;
}

interface ICircle {
    kind: 'circle';
    radius: number;
}

type TShape = IRectangle | ICircle;

let aa: TShape = {
    kind: 'circle',
    radius: 10
}
console.log(aa.radius) // 10
aa = {
    kind: 'rectangle',
    width: 1
}
console.log(aa.width) // 1
  • 交叉类型 交叉类型是将多个类型合并为一个类型
interface Person {
    name: string
    age: number
}
interface Student {
    school: string
}
type StudentInfo = Person & Student

const stu: StudentInfo = {
    name: 'Tom',
    age: 23,
    school: 'Oxford',
}
  • 类型断言
  1. as 操作符
interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}
// 对于一些不知道参数类型,可以断言为any, 或者参数为多个类型时,断言为某个类型
function isFish(animal: Cat | Fish) {
    if (typeof (animal as Fish).swim ==='function') { //此处用animal.swim报错
        return true;
    }
    return false;
}
  1. !非空断言操作符
// 忽略 undefined 和 null 类型
interface IObj {b:1}
const a: IObj | undefined = undefined;
const obj: IObj = a!;
const b: number = a!.b;


// 调用函数时忽略 undefined 类型
type NumGenerator = () => number;
function myFunc(numGenerator?: NumGenerator) { // 等同:numGenerator: NumGenerator | undefined
    // Cannot invoke an object which is possibly 'undefined'.(2722)
    const num1 = numGenerator(); // Error
    const num2 = numGenerator!(); //OK
}

接口

接口是描述值的结构,属性如下:

  1. 任意属性(字符串索引类型)、可选属性 [propName:string]
interface IPerson {
    readonly phone: number; // 只读属性
    name: string; // 固定属性,必要
    age?: number; // 可选属性,非必要
    [propName: string]: string | number | string[] | undefined; // 包含可选属性功能age?需要undefined
}

let tom: IPerson = {
    name: 'Tom',
    gender: 'male', // 任意一个
    phone: 188888888
};

tom.phone = 19999999 // Cannot assign to 'phone' because it is a read-only property.

2.type(类型别名)和interface(接口)区别

interface 和 type 两个关键字的含义和功能都非常的接近

  • interface:
    1. 同名的 interface 自动合并
    2. 只能表示 object、class、function 类型
  • type:
    1. 不仅仅能够表示 object、class、function
    2. 不能重名(自然不存在同名聚合了),type支持复杂的类型操作
    3. 与 interface 不同,type 还可以用来标书其他的类型,比如基本数据类型、元素、并集等
type TName = string;
type TNameResolver = () => string;
type TNameOrResolver = Name | NameResolver;

3.函数

// 函数声明方式1
type LongHand = {
    (a: number): number;
};
// 函数声明方式2
type ShortHand = (a: number) => number;

// 以上方式相当于
function person(a: number): number { return a }
const person: LongHand = (a) => { return a} // 这里有类型推断,省略了(a: number): number =>

4.类与继承

// 接口可以继承多个接口,合并所有接口的声明字段
interface Shape {
    color: string;
}
    
interface PenStroke {
    penWidth: number;
}
    
interface Square extends Shape, PenStroke {
    sideLength: number;
}
    
let square = <Square> {};
square.color = 'red'
square.sideLength = 10;

// 接口继承类,合并类的成员和结构
class Point {
    x: number;
    y: number;
    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};

// 以react为例:
// class类型
export default class VisibleTodoList extends React.Component<{a:number}>
// hook类型
export default const EditPlanbook: React.FC<{a: number}>{}

声明合并

声明同名的函数会合并,声明同名的接口会合并,声明同名的类会合并

声明文件

声明文件须以 .d.ts 为后缀

  • 声明模块:
// 转dayjs为moment
declare module 'moment' {
    import dayjs, { Dayjs } from 'dayjs';
    export default dayjs;
}
import moment from 'moment'; 

// 声明新模块,使m有fn函数
declare module "SomeModule" {
    export function fn(): string;
}
import * as m from "SomeModule";
m.fn()   
  • 全局模块:

1.定义全局默认类型

declare global {
    // 给全局String类型加prependHello方法
    interface String {
        prependHello(): string;
    }
    // 给全局window类型加projectConf、projectMainConf、eventBus属性
    interface Window {
        projectConf: Record<string, any>;
        projectMainConf: Record<string, any>;
        eventBus?: any;
    }
}
// 注意: 修改"全局声明"必须在模块内部, 所以至少要有 export{}字样
// 不然会报错❌: 全局范围的扩大仅可直接嵌套在外部模块中或环境模块声明中
export {};
'bar'.prependHello();

2.declare全局自定义类型

// 通用接口返回类型,.d.ts默认全局
declare interface ApiResp<T> {
    data: T;
    code: number;
    msg: string;
    message: string;
}

3.其余的还有: declare namespace 声明(含有子属性的)全局对象

泛型

泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。

function createArray<T>(length: number, value: T): Array<T> {
    let result: T[] = [];
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }
    return result;
}
createArray<string>(3, 'x'); // ['x', 'x', 'x']
createArray(3, 'x'); // ['x', 'x', 'x'],'x'会自动被推断为string

在函数名后添加了 ,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array 中即可使用了

  • response内容的定义用泛型
declare interface ApiResp<T> {
    data: T;
    code: number;
    message: string;
}

type TPlanbookRes = {
    list: string[];
    totalCount: number;
}

interface SpeechMgmtProps {
    getPlanbookList: () => Promise<ApiResp<TPlanbookRes>>;
}
  • 请求方式,如:axios
get方法:
interface AxiosInstance{
    get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;
}

axios.get<TPlanbookRes>(`/app/rooms/uniqs/url`);

泛型工具类型-常用的

  • Record:以 typeof 格式快速创建一个类型,此类型包含一组指定的属性且都是必填。
type Coord = Record<'x' | 'y', number>;
// 等同于
type Coord = {
    x: number;
    y: number;
}
  • Partial: 将类型定义的所有属性都修改为可选。
type Coord = Partial<Record<'x' | 'y', number>>;
// 等同于
type Coord = {
    x?: number;
    y?: number;
}
  • Pick:从类型定义的属性中,选取指定一组属性,返回一个新的类型定义。
type Coord = Record<'x' | 'y', number>;
type CoordX = Pick<Coord, 'x'>;
// 等用于
type CoordX = {
    x: number;
}
  • Omit:从类型定义的属性中,排除某个属性
type Omit<T, K> 等于 Pick<T, Exclude<keyof T, K>> 
// 使用:
type Foo = Omit<{name: string, age: number}, 'name'>
let aa: Foo = {age: 1} // 已无name属性

工具类型源码

编译上下文

  • 如果一个目录下存在一个tsconfig.json文件,那么它意味着这个目录是TypeScript项目的根目录。 tsconfig.json文件中指定了用来编译这个项目的根文件和编译选项
  • 使用"files"属性,指定需要编译的文件
{
    "compilerOptions": {},
    "files": [
        "./some/file.ts"
    ]
}
  • 使用 include 和 exclude 选项来指定需要包含的文件和排除的文件
{
    "include": [
         "src/**/*"
     ],
     "exclude": [
         "node_modules",
         "**/*.spec.ts"
     ]
}
  • 可以通过 compilerOptions 来定制你的编译选项

    如果"files"和"include"都没有被指定,编译器默认包含当前目录和子目录下所有的TypeScript文件,可使用compilerOptions来定制你的编译选项

1.@types:默认所有可见的"@types"包会在编译过程中被包含进来, node_modules/@types文件夹下以及它们子文件夹下的所有包都是可见的。

2.ypeRoots:如果指定了typeRoots,只有typeRoots下面的包才会被包含进来。 如:

{
    "compilerOptions": {
        "typeRoots" : ["./typings"]
    }
}

这个配置文件会包含所有./typings下面的包,而不包含./node_modules/@types里面的包

3.types:如果指定了types,只有被列出来的包才会被包含进来。同时可指定"types": []来禁用自动引入@types包

{
    "compilerOptions": {
            "types" : ["node", "lodash", "express"]
    }
}

这个配置文件将仅会包含 ./node_modules/@types/node,./node_modules/@types/lodash和./node_modules/@types/express。/@types/。 node_modules/@types/*里面的其它包不会被引入进来。

  • compilerOptions详细解释如下
{
     "compilerOptions": {

         /* 基本选项 */
         "target": "es5",                       // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES6'/'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
         "module": "commonjs",                  // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
         "lib": [],                             // 指定要包含在编译中的库文件
         "allowJs": true,                       // 允许编译 javascript 文件
         "checkJs": true,                       // 报告 javascript 文件中的错误
         "jsx": "preserve",                     // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
         "declaration": true,                   // 生成相应的 '.d.ts' 文件
         "sourceMap": true,                     // 生成相应的 '.map' 文件
         "outFile": "./",                       // 将输出文件合并为一个文件
         "outDir": "./",                        // 指定输出目录
         "rootDir": "./",                       // 用来控制输出目录结构 --outDir.
         "removeComments": true,                // 删除编译后的所有的注释
         "noEmit": true,                        // 不生成输出文件
         "importHelpers": true,                 // 从 tslib 导入辅助工具函数
         "isolatedModules": true,               // 将每个文件作为单独的模块 (与 'ts.transpileModule' 类似).

         /* 严格的类型检查选项 */
         "strict": true,                        // 启用所有严格类型检查选项
         "noImplicitAny": true,                 // 在表达式和声明上有隐含的 any类型时报错
         "strictNullChecks": true,              // 启用严格的 null 检查
         "noImplicitThis": true,                // 当 this 表达式值为 any 类型的时候,生成一个错误
         "alwaysStrict": true,                  // 以严格模式检查每个模块,并在每个文件里加入 'use strict'
         
         /* 额外的检查 */
         "noUnusedLocals": true,                // 有未使用的变量时,抛出错误
         "noUnusedParameters": true,            // 有未使用的参数时,抛出错误
         "noImplicitReturns": true,             // 并不是所有函数里的代码都有返回值时,抛出错误
         "noFallthroughCasesInSwitch": true,    // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)

         /* 模块解析选项 */
         "moduleResolution": "node",            // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
         "baseUrl": "./",                       // 用于解析非相对模块名称的基目录
         "paths": {},                           // 模块名到基于 baseUrl 的路径映射的列表
         "rootDirs": [],                        // 根文件夹列表,其组合内容表示项目运行时的结构内容
         "typeRoots": [],                       // 包含类型声明的文件列表
         "types": [],                           // 需要包含的类型声明文件名列表
         "allowSyntheticDefaultImports": true,  // 允许从没有设置默认导出的模块中默认导入。

         /* Source Map Options */
         "sourceRoot": "./",                    // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
         "mapRoot": "./",                       // 指定调试器应该找到映射文件而不是生成文件的位置
         "inlineSourceMap": true,               // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
         "inlineSources": true,                 // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性

         /* 其他选项 */
         "experimentalDecorators": true,        // 启用装饰器
         "emitDecoratorMetadata": true          // 为装饰器提供元数据的支持
     }
 }

PS: 常用第三方库-antd的ts记录

  1. Input:
  • e.currentTarget.value
onChange = (e: React.FormEvent<HTMLInputElement>) => {
    const newValue = e.currentTarget.value;
}
  • e.target.value
onChange = (e: React.ChangeEvent<HTMLInputElement>)=> {
    const newValue = e.target.value;
}
  1. Radio:
import { RadioChangeEvent } from 'antd/lib/radio';

onRadioChange = (e: RadioChangeEvent) => {}
  1. select:
import { SelectValue } from 'antd/lib/select';

4.RangePicker:

import { RangePickerProps } from 'antd/es/date-picker/generatePicker';

onChangeTime = (dates: RangePickerValue, dateStrings: string[])

import moment from 'moment';
type RangePickerValue = RangePickerProps<moment.Moment>['value'];
  1. pagination:
import { TablePaginationConfig } from 'antd/lib/table';

babel转译ts,在线编译ts

参考链接

typescript入门教程

typescript文档