首页 > 其他分享 >typescript 进阶(一)

typescript 进阶(一)

时间:2024-07-03 19:53:50浏览次数:18  
标签:EDirection typescript return 进阶 number 枚举 const type

前言

本文主要记录个人在使用 typescript 时的一些用法,介绍 typescript 。建议在阅读前先了解 typescript 的基础语法。

互斥键的类型

在 ts 官网的联合类型文档中有这样一种情况:

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "square"; x: number }
  | { kind: "triangle"; x: number; y: number };
 
function area(s: Shape) {
  if (s.kind === "circle") {
    return Math.PI * s.radius * s.radius;
  } else if (s.kind === "square") {
    return s.x * s.x;
  } else {
    return (s.x * s.y) / 2;
  }
}

在此种情况下 ts 可以正常判断这两种类型的联合, 但是我们这样判断:

function area(s: Shape) {
  if (s.radius) { // if 中判断修改
    return Math.PI * s.radius * s.radius;
  } else if (s.kind === "square") {
    return s.x * s.x;
  } else {
    return (s.x * s.y) / 2;
  }
}

点此在线查看

或者是这样, 没有 type 的情况:

type Shape =
  | { radius: number, cal: ()=>number}
  | { x: number }


function area(s: Shape) {
    if(s.cal){
        return s.cal()
    }else{
        return s.x * s.x;
    }
}

点此在线查看

这里就会报如下的错误:

Property 'cal' does not exist on type 'Shape'.
  Property 'cal' does not exist on type '{ x: number; }'.

ts 在联合类型中, 我们直接通过 . 获取的属性, 是必须在所有子类型中共有的

这里我们有 2 种结局方案

  1. 使用 in 操作符
type Shape =
    | { radius: number, cal: ()=>number}
    | { x: number }


function area(s: Shape) {
    if ('cal' in s) {
        return s.cal()
    } else {
        return s.x * s.x;
    }
}

点此在线查看

  1. 使用特殊的类型库来包装

函数类型

有时候函数我们也会当做对象来使用:

interface IFN {
    (): number;
    name: string
}

const a: IFN = () => {
    //...
    return 1
}

a.name = 'test'

同样地, 会有一些特殊的函数, 如 Date, 他有多套不同的函数:

new Date(1656953943886)
// Tue Jul 05 2022 00:59:03 GMT+0800 (中国标准时间)
// Date 对象

new Date('2022-12-1')
// Thu Dec 01 2022 00:00:00 GMT+0800 (中国标准时间)
// 也是 Date 对象

// ...

在 ts 的声明中他是这样被描述的

interface DateConstructor {
    new(): Date;
    new(value: number | string): Date;
    new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;
    (): string;
    readonly prototype: Date;
    parse(s: string): number;
    UTC(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number;
    now(): number;
}

字面量类型

// @errors: 2345
declare function handleRequest(url: string, method: "GET" | "POST"): void;
// ---cut---
const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);

点此在线查看

解决方案

  1. 使用泛型:
// Change 1:
const req = { url: "https://example.com", method: "GET" as "GET" };
// Change 2
handleRequest(req.url, req.method as "GET");
  1. as const
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method);

此例子在官网文档中也有提到: https://www.typescriptlang.org/docs/handbook/2/everyday-types.html

对象

重新映射

通过对象 as 重新映射出类型:

type Getters<Type> = {
    [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};
 
interface Person {
    name: string;
    age: number;
    location: string;
}
 
type LazyPerson = Getters<Person>;

// type LazyPerson = {
//  getName: () => string;
//  getAge: () => number;
//  getLocation: () => string;
// }

点此在线查看

映射中添加条件判断:

type ExtractPII<Type> = {
  [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
};
 
type DBFields = {
  id: { format: "incrementing" };
  name: { type: string; pii: true };
};
 
type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;

// type ObjectsNeedingGDPRDeletion = {
//     id: false;
//     name: true;
// }

点此在线查看

枚举

静态枚举

const enum ITypeEnums {
    Input ,
    Select
}

// 普通枚举:
 
enum ITypeEnums {
    Input ,
    Select
}

经过编译后:

var ITypeEnums2;
(function (ITypeEnums2) {
    ITypeEnums2[ITypeEnums2["Input"] = 0] = "Input";
    ITypeEnums2[ITypeEnums2["Select"] = 1] = "Select";
})(ITypeEnums2 || (ITypeEnums2 = {}));

很明显的是静态枚举消失了

这是 ts 为了避免在访问枚举值时额外的生成代码的代价

静态枚举的编译

const enum ITypeEnums {
    Input ,
    Select
}

let types = [
  ITypeEnums.Input,
  ITypeEnums.Select
];

const type: ITypeEnums.Input = 1
let types = [
    0 /* ITypeEnums.Input */,
    1 /* ITypeEnums.Select */
];
const type = 1;

枚举的选择

什么情况下选择枚举, 而什么情况下会选择对象

在一般情况下, 我们使用静态对象就够了:

const enum EDirection {
  Up,
  Down,
  Left,
  Right,
}
 
const ODirection = {
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3,
} as const

let a = ODirection.Up
// 提示 Up: 0

对状态进行多种判断时, 我们用到枚举的情况会更多(尤其是静态枚举)


const enum EDirection {
    Up,
    Down,
    Left,
    Right,
}

const getStatus = (status: EDirection) => {
    switch(status){
        case EDirection.Up:
            return 'success'
        case EDirection.Down:
            return 'fail'
        default:
            return null
    }
}

编译之后的结果:

const getStatus = (status) => {
    switch (status) {
        case 0 /* EDirection.Up */:
            return 'success';
        case 1 /* EDirection.Down */:
            return 'fail';
        default:
            return null;
    }
};

点击在线查看

比较下非静态枚举的编译:

var EDirection;
(function (EDirection) {
    EDirection[EDirection["Up"] = 0] = "Up";
    EDirection[EDirection["Down"] = 1] = "Down";
    EDirection[EDirection["Left"] = 2] = "Left";
    EDirection[EDirection["Right"] = 3] = "Right";
})(EDirection || (EDirection = {}));
const getStatus = (status) => {
    switch (status) {
        case EDirection.Up:
            return 'success';
        case EDirection.Down:
            return 'fail';
        default:
            return null;
    }
};

通过此种静态枚举的方案来判断类型, 比较 Object['name'] 的方式和普通枚举的方式来说,
性能更好, 可维护性也更高

有静态方法的枚举

你可以使用 enum + namespace 的声明的方式向枚举类型添加静态方法。

这里的枚举只支持普通枚举


enum EDirection {
  Up,
  Down,
  Left,
  Right,
}


namespace EDirection {
  export function go(type: EDirection) {
    switch (type) {
      case EDirection.Up:
      case EDirection.Down:
        return false;
      default:
        return true;
    }
  }
}

EDirection.go(EDirection.Down)

搭配使用可以在状态的基础上, 作出各种变化和判断方法

标签:EDirection,typescript,return,进阶,number,枚举,const,type
From: https://www.cnblogs.com/Grewer/p/18282448

相关文章

  • python-进阶2
    三大特征1.继承1.1单继承1.2多继承1.3方法调用顺序1.4调用父类方法1.5super1.6多层继承2封装3多态3.1入门3.2条件3.3优势4抽象5类属性与方法5.1类属性5.2类方法5.3静态方法1.继承面向对象中的继承:指的是多个类之间的所属关系,即子类默认......
  • Power BI进阶秘籍,干货满满!如何将度量值转化为切片器(动态切换分析指标),实操指南来了!
    PowerBI进阶秘籍,干货满满!如何将度量值转化为切片器(动态切换分析指标),实操指南来了! 想要在PowerBI中让度量值也能像维度一样灵活筛选?没问题,这里就为你揭秘如何将度量值转化为切片器(动态切换分析指标)的实用方法! 一、了解基础:首先,要知道PowerBI原生不支持直接将度量值作为切......
  • TypeScript使用
    检查TypeScript配置:确保您的Vue项目已正确配置TypeScript。您可以检查是否安装了@vue/cli-plugin-typescript插件,并且tsconfig.json文件配置正确。类型定义:确保您正确定义了变量、函数和组件的类型。在Vue组件中,可以使用TypeScript的类型保护帮助我明确变量的类型在T......
  • stable diffusion ControlNet使用介绍与进阶技巧
    ControlNet是什么?固定构图、定义姿势、描绘轮廓、单凭线稿就能生成一张丰满精致的插画……它几乎无所不能。有人把它称为AI绘画界的“革命性”突破,但在我看来,它不过是StableDiffusion迈向“工业化”的第一步。ControlNet扩展与模型下载地址扩展地址:https://github.com/Mikubil......
  • TypeScript中,如何利用数组生成一个联合类型
    本文由ChatMoney团队出品在开发中我们常常会遇到这样一个问题,代码如下:constarr=["a","b","c","d","e","f","g","h","i","j","k","l&qu......
  • TypeScript中,如何利用数组生成一个联合类型
    本文由ChatMoney团队出品在开发中我们常常会遇到这样一个问题,代码如下:constarr=["a","b","c","d","e","f","g","h","i","j","k","l&qu......
  • Java(Spring Boot)编程思想学习进阶书籍
    1、SpringBoot编程思想(核心篇)该书是《SpringBoot编程思想》的核心篇,开篇总览SpringBoot核心特性,接着讨论自动装配(Auto-Configuration)与SpringApplication。《SpringBoot编程思想(核心篇)》的讨论以SpringBoot为中心,议题发散至Spring技术栈、JSR及Java。希望透过全局的视角,......
  • SHELL脚本学习(十四)gawk进阶
    一、使用变量gawk支持两种变量内建变量自定义变量1.1内建变量1.1.1字段和记录分隔符变量数据字段变量允许使用美元符号$和位置来引用对应的字段。$1对应第一个数据字段,$2对应第二个数据字段,以此类推。数据字段用字段分隔符划定。默认情况下,字段分隔符是一个空......
  • Python进阶教程--科学计算基础软件包NumPy
    NumPy(NumericalPython)是一个开源的Python库,用于科学计算。它提供了一个高性能的多维数组对象和用于处理这些数组的工具。NumPy是Python科学计算的基础库,被广泛用于数据分析、机器学习、科学计算等领域。1.1NumPy概述NumPy是Python的一个扩展库,主要用于处理大型多维数组......
  • JavaScript 进阶之旅:Symbol 引领标识符新纪元
    个人主页:学习前端的小z个人专栏:JavaScript精粹本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结,欢迎大家在评论区交流讨论!文章目录......