首页 > 其他分享 >TypeScript很麻烦,不想使用! 转载

TypeScript很麻烦,不想使用! 转载

时间:2024-11-25 10:33:14浏览次数:8  
标签:TypeScript string 代码 number 类型 组件 麻烦 interface 转载

原文链接:https://juejin.cn/post/7344282440725577765

本文已经授权【稀土掘金技术社区】官方公众号独家原创发布。

前言

最近,我们部门在开发一个组件库时,我注意到一些团队成员对使用TypeScript表示出了抵触情绪,他们常常抱怨说:“TypeScript太麻烦了,我们不想用!”起初,我对此感到困惑:TypeScript真的有那么麻烦吗?然而,当我抽时间审查队伍的代码时,我终于发现了问题所在。在这篇文章中,我想和大家分享我的一些发现和解决方案。

一、类型复用不足

在代码审查过程中,我发现了大量的重复类型定义,这显著降低了代码的复用性。

进一步交流后,我了解到许多团队成员并不清楚如何在TypeScript中复用类型。TypeScript允许我们使用typeinterface来定义类型。

当我询问他们typeinterface之间的区别时,大多数人都表示不清楚,这也就难怪他们不知道如何有效地复用类型了。

type定义的类型可以通过交叉类型(&)来进行复用,而interface定义的类型则可以通过继承(extends)来实现复用。值得注意的是,typeinterface定义的类型也可以互相复用。下面是一些简单的示例:

复用type定义的类型:

  ts 代码解读 复制代码
type Point = {
  x: number;
  y: number;
};

type Coordinate = Point & {
  z: number;
};

复用interface定义的类型:

  ts 代码解读 复制代码
interface Point {
  x: number;
  y: number;
};

interface Coordinate extends Point {
  z: number;
}

interface复用type定义的类型:

  ts 代码解读 复制代码
type Point = {
  x: number;
  y: number;
};

interface Coordinate extends Point {
  z: number;
}

type复用interface定义的类型:

  ts 代码解读 复制代码
interface Point {
  x: number;
  y: number;
};

type Coordinate = Point & {
  z: number;
};

二、复用时只会新增属性的定义

我还注意到,在类型复用时,团队成员往往只是简单地为已有类型新增属性,而忽略了更高效的复用方式。

例如,有一个已有的类型Props需要复用,但不需要其中的属性c。在这种情况下,团队成员会重新定义Props1,仅包含Props中的属性ab,同时添加新属性e

  ts 代码解读 复制代码
interface Props {
  a: string;
  b: string;
  c: string;
}

interface Props1 {
  a: string;
  b: string;
  e: string;
}

实际上,我们可以利用TypeScript提供的工具类型Omit来更高效地实现这种复用。

  ts 代码解读 复制代码
interface Props {
  a: string;
  b: string;
  c: string;
}

interface Props1 extends Omit<Props, 'c'> {
  e: string;
}

类似地,工具类型Pick也可以用于实现此类复用。

  ts 代码解读 复制代码
interface Props {
  a: string;
  b: string;
  c: string;
}

interface Props1 extends Pick<Props, 'a' | 'b'> {
  e: string;
}

OmitPick分别用于排除和选择类型中的属性,具体使用哪一个取决于具体需求。

三、未统一使用组件库的基础类型

在开发组件库时,我们经常面临相似功能组件属性命名不一致的问题,例如,用于表示组件是否显示的属性,可能会被命名为showopenvisible。这不仅影响了组件库的易用性,也降低了其可维护性。

为了解决这一问题,定义一套统一的基础类型至关重要。这套基础类型为组件库的开发提供了坚实的基础,确保了所有组件在命名上的一致性。

以表单控件为例,我们可以定义如下基础类型:

  ts 代码解读 复制代码
import { CSSProperties } from 'react';

type Size = 'small' | 'middle' | 'large';

type BaseProps<T> = {
  /**
   * 自定义样式类名
   */
  className?: string;
  /**
   * 自定义样式对象
   */
  style?: CSSProperties;
  /**
   * 控制组件是否显示
   */
  visible?: boolean;
  /**
   * 定义组件的大小,可选值为 small(小)、middle(中)或 large(大)
   */
  size?: Size;
  /**
   * 是否禁用组件
   */
  disabled?: boolean;
  /**
   * 组件是否为只读状态
   */
  readOnly?: boolean;
  /**
   * 组件的默认值
   */
  defaultValue?: T;
  /**
   * 组件的当前值
   */
  value?: T;
  /**
   * 当组件值变化时的回调函数
   */
  onChange: (value: T) => void;
}

基于这些基础类型,定义具体组件的属性类型变得简单而直接:

  ts 代码解读 复制代码
interface WInputProps extends BaseProps<string> {
  /**
   * 输入内容的最大长度
   */
  maxLength?: number;
  /**
   * 是否显示输入内容的计数
   */
  showCount?: boolean;
}

通过使用type关键字定义基础类型,我们可以避免类型被意外修改,进而增强代码的稳定性和可维护性。

四、处理含有不同类型元素的数组

在审查自定义Hook时,我发现团队成员倾向于返回对象,即使Hook只返回两个值。

虽然这样做并非错误,但它违背了自定义Hook的一个常见规范:当Hook返回两个值时,应使用数组返回。

团队成员解释说,他们不知道如何定义含有不同类型元素的数组,通常会选择使用any[],但这会带来类型安全问题,因此他们选择返回对象。

实际上,元组是处理这种情况的理想选择。通过元组,我们可以在一个数组中包含不同类型的元素,同时保持每个元素类型的明确性。

  ts 代码解读 复制代码
function useMyHook(): [string, number] {
  return ['示例文本', 42];
}

function MyComponent() {
  const [text, number] = useMyHook();
  console.log(text);  // 输出字符串
  console.log(number);  // 输出数字
  return null;
}

在这个例子中,useMyHook函数返回一个明确类型的元组,包含一个string和一个number。在MyComponent组件中使用这个Hook时,我们可以通过解构赋值来获取这两个不同类型的值,同时保持类型安全。

五、处理参数数量和类型不固定的函数

审查团队成员封装的函数时,我发现当函数的参数数量不固定、类型不同或返回值类型不同时,他们倾向于使用any定义参数和返回值。

他们解释说,他们只知道如何定义参数数量固定、类型相同的函数,对于复杂情况则不知所措,而且不愿意将函数拆分为多个函数。

这正是函数重载发挥作用的场景。通过函数重载,我们可以在同一函数名下定义多个函数实现,根据不同的参数类型、数量或返回类型进行区分。

  ts 代码解读 复制代码
function greet(name: string): string;
function greet(age: number): string;
function greet(value: any): string {
  if (typeof value === "string") {
    return `Hello, ${value}`;
  } else if (typeof value === "number") {
    return `You are ${value} years old`;
  }
}

在这个例子中,我们为greet函数提供了两种调用方式,使得函数使用更加灵活,同时保持类型安全。

对于箭头函数,虽然它们不直接支持函数重载,但我们可以通过定义函数签名的方式来实现类似的效果。

  typescript 代码解读 复制代码
type GreetFunction = {
  (name: string): string;
  (age: number): string;
};

const greet: GreetFunction = (value: any): string => {
  if (typeof value === "string") {
    return `Hello, ${value}`;
  } else if (typeof value === "number") {
    return `You are ${value} years old.`;
  }
  return '';
};

这种方法利用了类型系统来提供编译时的类型检查,模拟了函数重载的效果。

六、组件属性定义:使用type还是interface

在审查代码时,我发现团队成员在定义组件属性时既使用type也使用interface

询问原因时,他们表示两者都可以用于定义组件属性,没有明显区别。

由于同名接口会自动合并,而同名类型别名会冲突,我推荐使用interface定义组件属性。这样,使用者可以通过declare module语句自由扩展组件属性,增强了代码的灵活性和可扩展性。

  ts 代码解读 复制代码
interface UserInfo {
  name: string;
}
interface UserInfo {
  age: number;
}

const userInfo: UserInfo = { name: "张三", age: 23 };

结语

TypeScript的使用并不困难,关键在于理解和应用其提供的强大功能。如果你在使用TypeScript过程中遇到任何问题,不清楚应该使用哪种语法或技巧来解决,欢迎在评论区留言。我们一起探讨,共同解决TypeScript中遇到的挑战。


作者:前端大骆
链接:https://juejin.cn/post/7344282440725577765
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

标签:TypeScript,string,代码,number,类型,组件,麻烦,interface,转载
From: https://www.cnblogs.com/testzcy/p/18567099

相关文章

  • VsCode 快捷键[转载]
    前言VSCode的快捷键继承了一些IDE风格,有VS的身影,也有Emacs的身影。。简言之,内置快捷键玩熟了,效率提高不是一点两点。VsCode快捷键有五种组合方式(科普)Ctrl+Shift+?:这种常规组合按钮Ctrl+VCtrl+V:同时依赖一个按键的组合Shift+Vc:先组合后单键的输入Ctrl......
  • Vue3 + TypeScript:从环境搭建到组件通信的完整前端开发教程
    在前端开发领域,Vue3与TypeScript的组合备受青睐。Vue3带来高效灵活的开发体验,TypeScript则提供强大的类型安全和可维护性。本文将详细介绍如何使用Vue3和TypeScript进行开发,文章内容将按照以下顺序展开:一、环境准备1.安装Node.js:从Node.js官方网站下载并安装适合......
  • TypeScript新手学习教程--接口
    TypeScript也支持接口,跟Java类似,这对于学习过java,c#,php语言的人更容易上手,虽然类似,但是也有不同,下面开始学习。1、 接口声明TypeScript的核心原则之一是对值所具有的结构进行类型检查。它有时被称做“鸭式辨型法”或“结构性子类型化”。在TypeScript里,接口的作用就是为......
  • 软件开发----Java基础每日刷题(转载于牛客)
    1.        A 是抽象父类或接口, B , C 派生自 A ,或实现 A ,现在 Java 源代码中有如下声明:1. A a0=new A();2. A a1=new B();3. A a2=new C();问以下哪个说法是正确的?()A        第1行不能通过编译B        第1、2行能通......
  • TypeScript语法总结
    1.Typescript概述融合了后端面向对象思想的超级版的JavaScript语言。​TypeScript是JavaScript的超集,扩展了JavaScript的语法。特点:(1)TypeScript:【静态类型检查器】可在编译时检查错误(2)TypeScript为JS的超集(3)TS===JS+【类型】js有的ts都有(4)TS规范了JS......
  • 深入理解 synchronized 的锁升级【转载】
    目录本文转载自:前言锁升级无锁偏向锁轻量级锁重量级锁总要有总结锁优化本文转载自:深入理解synchronized的锁升级-掘金(juejin.cn)前言        最近看到一道有关synchronized关键字的面试题:不同JDK版本对synchronized有何优化?这道面试题的目......
  • TypeScript在Vue中的使用-------ref
    我们平时的写法import{ref}from"vue";constmsg=ref("你好世界");使用TS的写法import{ref}from"vue";constmsg=ref<string>("你好世界");listType表示数组里面放对象,我们可以用如下的方法进行调用typelistType={id:numbername:......
  • 转载 fastapi 部署 原文链接:https://blog.csdn.net/FrenzyTechAI/article/details/132
    sudoadd-apt-repositoryppa:deadsnakes/ppasudoaptupdatesudoaptinstallpython3.12python3.12-venv-ysudoaptinstallsupervisorsudoaptinstallsupervisornginx-y启用并启动Supervisor:sudosystemctlenablesupervisorsudosystemctlstartsupervisor使用ena......
  • TypeScript:模块
    一、前言关于术语的一点说明:请务必注意一点,TypeScript1.5里术语名已经发生了变化。“内部模块”现在称做“命名空间”。“外部模块”现在则简称为“模块”,这是为了与ECMAScript2015里的术语保持一致,(也就是说moduleX{相当于现在推荐的写法namespaceX{)。......
  • 【TypeScript】函数详解:参数和返回值的类型注解
    文章目录一、函数基础概述1.参数类型注解2.参数个数检查3.可选参数和默认值二、返回值类型注解1.基本的返回值类型注解2.自动类型推断三、异步函数与Promise返回值类型四、匿名函数与上下文类型推断五、高阶函数与回调六、总结TypeScript是JavaScript的......