广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >如何理解Typescript代码
  • 580
分享到

如何理解Typescript代码

2024-04-02 19:04:59 580人浏览 安东尼
摘要

这篇文章主要介绍“如何理解typescript代码”,在日常操作中,相信很多人在如何理解Typescript代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Type

这篇文章主要介绍“如何理解typescript代码”,在日常操作中,相信很多人在如何理解Typescript代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Typescript代码”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、基础规范

(1)常量

常量必须命名, 在做逻辑判断的时候,也不允许直接对比没有命名的常量。

  •  错误的书写 

switch(num){        case 1:          ...        case 3:          ...        case 7:          ...   }   if(x === 0){        ...   }

上述的例子中,根本不知道1 3 7 对应的是什么意思,这种写法就基本上没有可读性。

  •  正确的写法   

enum DayEnum {         oneDay = 1,         threeDay = 3,         oneWeek = 7,     }     let num  = 1;     switch(num){         case DayEnum.oneDay:         ...         case DayEnum.threeDay:         ...         case DayEnum.oneWeek:         ...     }    const RightCode = 0;    if(x === RightCode)

从上述正确的写法可以看出来,常量有了命名,在switch或者if等逻辑判断的时候,我们可以从变量名得知常量的具体含义,增加了可读性。

(2)枚举

除了常量枚举外,在Typescript的编译阶段,枚举会生成一个maping对象,如果不是字符串枚举,甚至会生成一个双向的mapping。因此在我们的业务代码中,有了枚举,就不需要一个与枚举值相关的数组

  •  错误的写法 

enum FruitEnum {         tomato = 1,         banana =  2,         apple = 3  }  const FruitList = [    {       key:1,       value: 'tomato'    },{       key:2,       value: 'banana'    },{       key:3,       value: 'apple'    }  ]

这里错误的原因是冗余,我们要得到一个FruitList,并不需要new一个,而是可以直接根据FruitEnum的枚举来生成一个数组,原理就是我们之前所说的Typescript的枚举,除了常量枚举外,在编译的时候是会生成一个map对象的。

  •  正确的写法 

enum FruitEnum {      tomato = 1,      banana =  2,      apple = 3  }  const FruitList = Object.entries(FruitEnum)

上述就是正确的写法,这种写法不仅仅是不冗余,此外,如果修改了枚举的类型,我们只要直接修改枚举,这样衍生的数组也会改变。

除此之外,字符串枚举值和字符串是有本质区别的,在定义类型的时候请千万注意,要不然会让你写的代码很冗余。

  •  错误的用法 

enum GenderEnum{    'male' = '男生',    'female' = '女生'  }  interface IPerson{     name:string     gender:string  }  let bob:IPerson = {name:"bob",gender:'male'}  <span>{Gender[bob.gender as keyof typeof GenderEnum]}</span>

上述的错误的原因就是IPerson的类型定义中,gender不应该是string,而应该是一个枚举的key,因此,在将string转枚举值的时候,必须增加一个as keyof typeof GenderEnum的断言。

  •   正确的写法 

enum GenderEnum{    'male' = '男生',    'female' = '女生'  }  interface IPerson{     name:string     gender:keyof typeof GenderEnum  }  let bob:IPerson = {name:"bob",gender:'male'}  <span>{Gender[bob.gender]}</span>

上述 就是正确的写法,字符串枚举和字符串类型是有 明显区别的,当某个变量需要使用到枚举时,不能将他定义成string。

(3)ts-ignore & any

Typescript中应该严格禁止使用ts-ignore,ts-ignore是一个比any更加影响Typescript代码质量的因素。对于any,在我的项目中曾一度想把any也禁掉,但是有一些场景中是需要使用any的,因此没有粗鲁的禁止any的使用。但是绝大部分场景下,你可能都不需要使用any.需要使用any的场景,可以case by case的分析。

  •  错误使用ts-ignore的场景 

//@ts-ignore    import Plugin from 'someModule' //如果someModule的声明不存在   Plugin.test("hello world")

上述就是最经典的使用ts-ignore的场景,如上的方式使用了ts-ignore.那么Typescript会认为Plugin的类型是any。正确的方法通过declare module的方法自定义需要使用到的类型.

  •  正确的方法 

import Plugin from 'someModule'  declare module 'someModule' {      export type test = (arg: string) => void;  }

在module内部可以定义声明,同名的声明遵循一定 的合并原则,如果要扩展三方模块,declare module是很方便的。

同样的大部分场景下,你也不需要使用any,部分场景下如果无法立刻确定某个值的类型,我们可以 用unknown来代替使用any。

any会完全失去类型判断,本身其实是比较危险的,且使用any就相当于放弃了类型检测,也就基本上放弃了typescript。举例来说:

let fish:any = {         type:'animal',         swim:()=> {             }  }  fish.run()

上述的例子中我们调用了一个不存在的方法 ,因为使用了any,因此跳过了静态类型检测,因此是不安全的。运行时会出错,如果无法立刻确定某个值的类型,我们可以 用unknown来代替使用any。

let fish:unknown = {        type:'animal',        swim:()=> {            }  }  fish.run() //会报错

unkonwn是任何类型的子类型,因此跟any一样,任意类型都可以赋值给unkonwn。与any不同的是,unkonwn的变量必须明确自己的类型,类型收缩或者类型断言后,unkonwn的变量才可以正常使用其上定义的方法和变量。

简单来说,unkonwn需要在使用前,强制判断其类型。

(4)namespace

Typescript的代码中,特别是偏业务的开发中,你基本上是用不到namespace的。此外module在nodejs中天然支持,此外在es6(next)中 es module也成为了一个语言级的规范,因此Typescript官方也是推荐使用module。

namespace简单来说就是一个全局对象,当然我们也可以把namespace放在module中,但是namespace放在module中也是有问题的。

  •  错误的方法 

//在一个shapes.ts的模块中使用  export namespace Shapes {      export class Triangle {              }      export class Square {              }  }  //我们使用shapes.ts的时候  //shapeConsumer.ts  import * as shapes from "./shapes";  let t = new shapes.Shapes.Triangle(); // shapes.Shapes?
  •  正确的方法(直接使用module) 

export class Triangle {    }  export class Square {    }

上述直接使用module,就是正确的方法,在模块系统中本身就可以避免变量命名重复,因此namespace是没有意义的。

(5)限制函数参数的个数

在定义函数的时候,应该减少函数参数的个数,推荐不能超过3个。

  •  错误的用法 

function getList(searchName:string,pageNum:number,pageSize:number,key1:string,key2:string){     ...  }

不推荐函数的参数超过3个,当超过3个的时候,应该使用对象来聚合。

  • 正确的用法 

interface ISearchParams{     searchName:string;     pageNum:number;     pageSize:number;     key1:string;     key2:string;  }   function getList(params:ISearchParams){  }

同样的引申到React项目中,useState也是同理

const [searchKey,setSearchKey] = useState('');  const [current,setCurrent] = useState(1)  const [pageSize,setPageSize] = useState(10)  //错误的写法  const [searchParams,setSearchParams] = useState({     searchKey: '',     current:1,     pageSize:10  })  //正确的写法

(6)module模块尽量保证无副作用

请不要使用模块的副作用。要保证模块的使用应该是先import再使用。

  •  错误的方法 

//Test.ts  window.x = 1;  class Test{  }  let test = new Test()  //index.ts  import from './test'  ...

上述在index.ts中import的模块,其调用是在test.ts文件内部的,这种方法就是import了一个有副作用的模块。

正确的方法应该是保证模块非export变量的纯净,且调用方在使用模块的时候要先import,后调用。

  •  正确的方法 

//test.ts  class Test{     constructor(){        window.x = 1     }  }  export default Test  //index.ts  import Test from './test'  const t = new Test();

(7)禁止使用!.非空断言

非空断言本身是不安全的,主观的判断存在误差,从防御性编程的角度,是不推荐使用非空断言的。

  •  错误的用法 

let x:string|undefinedundefined = undefined  x!.toString()

因为使用了非空断言,因此编译的时候不会报错,但是运行的时候会报错.

比较推荐使用的是optional chaining。以?.的形式。

(8)使用typescript的内置函数

typescript的很多内置函数都可以复用一些定义。这里不会一一介绍,常见的有Partial、Pick、Omit、Record、extends、infer等等,如果需要在已有的类型上,衍生出新的类型,那么使用内置函数是简单和方便的。此外还可以使用 联合类型、交叉类型和类型合并。

  •  联合类型 

//基本类型  let x:number|string  x= 1;  x = "1"
//多字面量类型   let type:'primary'|'danger'|'warning'|'error' =  'primary'

值得注意的是字面量的赋值。

let type:'primary'|'danger'|'warning'|'error' =  'primary'  let test = 'error'  type = test  //报错  let test = 'error' as const   type =  test //正确
  •  交叉类型 

interface ISpider{     type:string     swim:()=>void  }  interface IMan{     name:string;     age:number;  }  type ISpiderISpiderMan = ISpider & IMan  let bob:ISpiderMan  = {type:"11",swim:()=>{},name:"123",age:10}
  •  类型合并

最后讲一讲类型合并,这是一种极其不推荐的方法。在业务代码中,不推荐使用类型合并,这样会增加代码的阅读复杂度。类型合并存在很多地方。class、interface、namespace等之间都可以进行类型合并,以interface为例:

interface Box {    height: number;    width: number;  }  interface Box {    scale: number;  }  let box: Box = { height: 5, width: 6, scale: 10 };

上述同名的interface Box是会发生类型合并的。不仅interface和 interface可以类型合并,class和interface,class和namesppace等等都可能存在同名类型合并,在业务代码中个人不推荐使用类型合并。

(9)封装条件语句以及ts的类型守卫

  • 错误的写法 

if (fsm.state === 'fetching' && isEmpty(listnode)) {   // ...  }
  •  正确的写法 

function shouldShowSpinner(fsm, listNode) {       return fsm.state === 'fetching' && isEmpty(listNode);  }     if (shouldShowSpinner(fsmInstance, listNodeInstance)) {       // ...     }

在正确的写法中我们封装了条件判断的逻辑成一个独立函数。这种写法比较可读,我们从函数名就能知道做了一个什么判断。

此外封装条件语句也可以跟ts的自定义类型守卫挂钩。来看一个最简单的封装条件语句的自定义类型守卫。

function IsString (input: any): input is string {       return typeof input === 'string';  }  function foo (input: string | number) {       if (IsString(input)) {          input.toString() //被判断为string       } else {          }  }

在项目中合理地使用自定义守卫,可以帮助我们减少很多不必要的类型断言,同时改善代码的可读性。

(10)不要使用非变量

不管是变量名还是函数名,请千万不要使用非命名,在业务中我就遇到过这个问题,后端定义了一个非命名形式的变量isNotRefresh:

let isNotRefresh = false  //是否不刷新,否表示刷新

isNotRefresh表示不刷新,这样定义的变量会导致跟这个变量相关的很多逻辑都是相反的。正确的形式应该是定义变量是isRefresh表示是否刷新。

let isRefresh = false  //是否刷新,是表示刷新

二、函数式

个人非常推荐函数式编程,主观的认为链式调用优于回调,函数式的方式又优于链式调用。近年来,函数式编程日益流行,Ramdajs、RxJS、cycleJS、lodashJS等多种开源库都使用了函数式的特性。本文主要介绍一下如何使用ramdajs来简化代码。

(1)声明式和命令式

个人认为函数声明式的调用比命令式更加简洁,举例来说:

//命令式  let names:string[] = []  for(let i=0;i<persons.length;i++){          names.push(person[i].name)  }  //声明式  let names = persons.map((item)=>item.name)

从上述例子我们可以看出来,明显函数调用声明式的方法更加简洁。此外对于没有副作用的函数,比如上述的map函数,完全可以不考虑函数内部是如何实现的,专注于编写业务代码。优化代码时,目光只需要集中在这些稳定坚固的函数内部即可。

(2)Ramdajs

推荐使用ramdajs,ramdajs是一款优秀的函数式编程库,与其他函数式编程库相比较,ramdajs是自动柯里化的,且ramdajs提供的函数从不改变用户已有数据。

来自最近业务代码中的一个简单的例子:

    const getList = async () => {        pipeWithP([            () => setLoading(true),            async () =>                request.get('', {                    params: {action: API.getList},                }),            async (res: IServerRes) => {                R.ifElse(                  R.isEqual(res.message === 'success'),                  () => setList(res.response.list);                )();            },            () => setLoading(false)        ])();    };

上述是业务代码中的一个例子,利用pipe可以使得流程的操作较为清晰,此外也不用定义中间变量。

再来看一个例子:

let persons = [        {username: 'bob', age: 30, tags: ['work', 'boring']},        {username: 'jim', age: 25, tags: ['home', 'fun']},        {username: 'jane', age: 30, tags: ['vacation', 'fun']}      ]

我们需要从这个数组中找出tags包含fun的对象。如果用命令式:

let NAME = 'fun'  let person;  for(let i=0;i<persons.length;i++){     let isFind = false     let arr = persons[i].tags;     for(let j = 0;j<arr.length;j++){        if(arr[i] === NAME){           isFind = true           break;        }     }     if(isFind){        personperson = person[i]        break;     }  }

我们用函数式的写法可以简化:

let person = R.filter(R.where({tags: R.includes('fun')}))

很明显减少了代码量且更加容易理解含义。

最后再来看一个例子:

const oldArr= [[[[[{name: 'yuxiaoliang'}]]]]];

我们想把oldArr这个多维数组,最内层的那个name,由小写转成大写,用函数式可以直接这样写。

R.map(atem =>       R.map(btem => R.map(ctem => R.map(dtem => R.map(etem => etem.name.toUpperCase())(dtem))(ctem))(btem))(atem),   )(arr);

到此,关于“如何理解Typescript代码”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: 如何理解Typescript代码

本文链接: https://www.lsjlt.com/news/84072.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何理解Typescript代码
    这篇文章主要介绍“如何理解Typescript代码”,在日常操作中,相信很多人在如何理解Typescript代码问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Type...
    99+
    2022-10-19
  • 如何理解TypeScript
    今天就跟大家聊聊有关如何理解TypeScript,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。前言TypeScript是强类型语言,所以相比于Jav...
    99+
    2022-10-19
  • 如何使用函数式TypeScript代码
    本篇文章给大家分享的是有关如何使用函数式TypeScript代码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。谈到函数式编程时,我们常提到机制...
    99+
    2022-10-19
  • 浅析如何将TypeScript转为GoLang代码
    近年来,TypeScript 和 GoLang 都成为了非常流行的编程语言。TypeScript 是微软推出的一种静态类型语言,可编译为 JavaScript。它具备了强类型检查、类、接口、泛型等特性,提高了代码的可读性和可维护性。而 Go...
    99+
    2023-05-14
  • 如何理解TypeScript枚举类型
    本篇内容主要讲解“如何理解TypeScript枚举类型”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解TypeScript枚举类型”吧!前言:TypeScript 在 ES 原有类型基础上...
    99+
    2023-06-25
  • 如何理解Redis 代码库源码
    本篇文章给大家分享的是有关如何理解Redis 代码库源码,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Redis是一个用ANSI C &nbs...
    99+
    2022-10-19
  • 如何使用函数式思维重构TypeScript 代码
    这篇文章给大家介绍如何使用函数式思维重构TypeScript 代码,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。谈到函数式编程时,我们常提到机制、方法,而不是核心原则。函数式编程不是关...
    99+
    2022-10-19
  • 如何理解低代码的兴起
    这篇文章主要讲解了“如何理解低代码的兴起”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解低代码的兴起”吧!低代码是一种近些年兴起的企业软件快速开发技术...
    99+
    2022-10-19
  • 如何理解.NET代码转换器
    这篇文章将为大家详细讲解有关如何理解.NET代码转换器,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。想把.NET的代码(C#和VB.NET)互转吗?或是转成Python或Ruby吗?在网站上...
    99+
    2023-06-17
  • 如何理解Java代码的内存管理
    这期内容当中小编将会给大家带来有关如何理解Java代码的内存管理,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。小编通过几个方面来介绍Java代码的内存管理。有的代码,GC根本就回收不了,直接系统挂掉。GC...
    99+
    2023-06-17
  • 如何理解Java SynDemo对象源代码
    本篇文章为大家展示了如何理解Java SynDemo对象源代码,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java SynDemo对象一直在我们的语言使用中使用,其实在不断的学习中我们还是在源代码...
    99+
    2023-06-17
  • 如何理解TypeScript中的子类型、逆变、协变
    这篇文章主要介绍“如何理解TypeScript中的子类型、逆变、协变”,在日常操作中,相信很多人在如何理解TypeScript中的子类型、逆变、协变问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方...
    99+
    2022-10-19
  • 如何理解代码的内存消耗么
    本篇内容介绍了“如何理解代码的内存消耗么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!不同语言的内存管理不同的编程语言各自的内存管理方式。C...
    99+
    2023-06-15
  • 如何使用TypeScript类型注解
    小编给大家分享一下如何使用TypeScript类型注解,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!类型注解TypeScript提供了很多数据类型,通过类型对变量进行限制,称之为类型注解,使用类型注解后,就不能够随意变更变...
    99+
    2023-06-29
  • Spring静态代理和动态代理代码详解
    本节要点:Java静态代理Jdk动态代理1 面向对象设计思想遇到的问题在传统OOP编程里以对象为核心,并通过对象之间的协作来形成一个完整的软件功能,由于对象可以继承,因此我们可以把具有相同功能或相同特征的属性抽象到一个层次分明的类结构体系中...
    99+
    2023-05-30
    spring 静态代理 动态代理
  • 如何解析Mina代码
    小编给大家分享一下如何解析Mina代码,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先,Mina是什么能帮我们做什么我研究一个新技术的时候,首先问的就是这样的问...
    99+
    2023-06-17
  • 如何理解声明式与命令式代码
    这篇文章主要讲解了“如何理解声明式与命令式代码”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解声明式与命令式代码”吧!命令式编程命令式编程是我们从As...
    99+
    2022-10-19
  • 如何理解代理ip
    这篇文章将为大家详细讲解有关如何理解代理ip,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。何谓代理IP,实际上是一种网络代理,使用户可以通过代理人访问想要浏览的网站。总的来说,代理服务是保护...
    99+
    2023-06-25
  • 如何通俗的解释TypeScript 泛型
    目录概述什么是泛型编译系统通俗的理解泛型泛型类其他泛型使用的通俗解释结语概述 在 TypeScript 中我们会使用泛型来对函数的相关类型进行约束。这里的函数,同时包含 class ...
    99+
    2022-11-12
  • Swin-Transformer(原理 + 代码)详解
    参考博文 图解Swin Transformer Swin-Transformer网络结构详解 【机器学习】详解 Swin Transformer (SwinT) 论文下载 (二)代码的下载与配置 2....
    99+
    2023-09-08
    深度学习 python 神经网络 机器学习 pytorch
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作