当前位置: 首页 > news >正文

TypeScript系列:第六篇 - 编写高质量的TS类型

掌握这些,ts类型声明事半功倍 💪🏻

不要做

  • 永远不要使用类型 NumberStringBooleanSymbolObject 这些类型指的是非原始装箱对象,使用 numberstringbooleansymbol 类型
  • 不要使用 any 作为类型,除非正在将 JavaScript 项目迁移到 TypeScript
  • 不要将返回类型 any 用于其值将被忽略的回调,使用返回类型 void,其可以防止意外地以未经检查的方式使用函数的返回值 const fun = (fn: () => void) => {};

declare 作用?

declare关键字在 TypeScript 中主要用于声明类型信息,而不是实际的实现代码。其帮助 TypeScript 理解代码中的类型结构,从而提供更好的类型检查和代码提示等功能。

声明全局变量类型

当在项目中使用了某些全局变量,而这些变量没有明确的类型定义时,可以使用declare来声明它们的类型。

declare const globalVar: string;

如,在 UmiJS 框架 中,针对全局变量声明类型:

// typings.d.ts
declare function log(info: string): void; 
declare global {type AnalysisFunction = (params: { pageId: string; eventId: string; ext?: object }) => void;interface Window: {// 基座挂载window判断权限方法PermissionAuth?: (params: {// 页面唯一标识pk: string;// 按钮唯一标识fk?: string;}) => boolean;}
}

声明模块

如果要使用一个外部模块,但这个模块没有提供 TypeScript 的类型定义文件(.d.ts),可以通过declare module来声明它的类型。

declare module 'my-custom-module' {export function doSomething(): void;
}

.d.ts.ts 区别?

  • .d.ts:第三方库提供类型声明、声明全局变量或全局类型、扩展现有模块的类型声明

    // jquery.d.ts
    declare var jQuery: {(selector: string): any;ajax: {(url: string, settings?: any): void;};
    };
    
  • .ts:定义实际的类型和接口,并且这些类型和接口将被项目中的其他代码使用时,或者在项目内部进行模块化开发时

    // user.ts
    export interface User {id: number;name: string;email: string;
    }
    

import typeimport 区别?

  • import type:用于导入类型信息,但不会将导入的模块包含在运行时代码中。它主要用于类型声明,不会影响最终的 JavaScript 输出

    // main.ts
    import type { User } from './types';
    
  • import:用于导入模块中的值(如变量、函数、类等),这些值在运行时会被加载和执行。它不仅用于类型声明,还用于实际的代码运行

extends 扩展类型

interface 上的 extends 关键字允许从其他命名类型复制成员,并添加任何新成员。

这对于减少类型声明的数量以及表明同一属性的几个不同的意图很有用。

interface Person {name: string;age: number;
}
// 类型扩展
interface Man extends Person {readonly sex: '男';
}interface SpecialSkill {fly: () => void;
}
// 也可以从多种类型扩展
interface Superman extends Man, SpecialSkill {}

typeofkeyof 区别?

  • typeof 操作符用于获取一个变量或属性的类型

  • keyof 操作符用于获取一个对象类型的所有键的联合类型

interface IPerson {name: string;age: number;
}type PersonKey = keyof IPerson; // 类型是 "name" | "age"
const p: PersonKey = 'age';
const pType = typeof p; // string

更多内容,可详见:TypeScript系列:第四篇 - typeof 与 keyof

extends keyof 类型约束

在动态访问和操作对象属性时保持类型安全,避免运行时错误。

<TData, TLabelKey extends keyof TData> 定义两个泛型参数TDataTLabelKey

  • TData表示传入的对象类型
  • TLabelKey表示对象中的某个键,该键必须是TData对象的一个键(通过extends keyof TData约束)
动态访问对象属性

动态地访问对象的某个属性时,可以使用这种约束来确保访问的属性是有效的。

interface TData {city: string;adcode: number;
}// labelKey必须是data对象的键之一
function getValue<TData, TLabelKey extends keyof TData>(data: TData, labelKey: TLabelKey): TData[TLabelKey] {return data[labelKey];
}
动态生成对象属性
interface TData {city: string;adcode: number;
}// labelKey必须是data对象的键之一,value的类型必须与data[labelKey]的类型一致
function setProperty<TData, TLabelKey extends keyof TData>(data: TData, labelKey: TLabelKey, value: TData[TLabelKey]): TData {data[labelKey] = value;return data;
}

!非空断言

在不进行任何显式检查的情况下从类型中删除 nullundefined

function liveDangerously(x?: number) {return x.toFixed(); 	// x可能为“未定义”return x!.toFixed();  // ✔️
}
  • 绕过类型检查:当确定一个变量不会是nullundefined,但 TypeScript 编译器无法确定时,使用 !来绕过类型检查
  • 避免编译错误:在某些情况下,TypeScript会报错,因为其认为一个变量可能是nullundefined。使用!可以避免编译错误

模板字符串类型的排列组合

获得一组规律固定,可由排列组合得到的联合类型

type A = 'a1' | 'a2';
type B = 'b1' | 'b2';type Products = `${A}-${B}`; // "a1-b1" | "a1-b2" | "a2-b1" | "a2-b2"

实用工具类型

interface A {a: number;b: number;c: number;
}
interface B {c: number;d: number;
}
方法作用示例结果
Partial<Type>构造一个将 Type 的所有属性设置为可选的类型Partial<A & B>{a?: number, b?: number, c?: number}
Pick<Type, Keys>Type 中选取一组属性 Keys来构造一个类型Pick<A, 'a'|'c'>{a: number, c: number}
Omit<Type, Keys>Type 中选择所有属性然后删除 Keys来构造一个类型Omit<A, 'a'|'c'>{b: number}
Extract<Type, Union>Type 中提取所有可分配给 Union 的联合成员来构造一个类型Extract<A|B, B>B
http://www.lryc.cn/news/578735.html

相关文章:

  • 宁德时代携手问界,以“厂中厂”模式加速扩产
  • 零信任安全管理系统介绍
  • 电机控制——电机位置传感器零位标定
  • (论文总结)语言模型中的多模态思维链推理
  • Cross-modal Information Flow in Multimodal Large Language Models
  • gateway白名单存储nacos,改成存储数据库
  • Wisdom SSH 与宝塔面板:深度对比剖析
  • wrap+aria2c提高下载速度
  • 【仿muduo库实现并发服务器】LoopThreadPool模块
  • C# WPF + Helix Toolkit 实战:用两种方式打造“六面异色立方体”
  • 锂离子电池均衡拓扑综述
  • Bootstrap 安装使用教程
  • tree 命令集成到 Git Bash:可视化目录结构的指南
  • Cereal中支持QString、QVector、QList、QMap
  • web开发,旅游景点管理系统推荐算法版本demo,基于asp.net,mvc,c#,sql server
  • 每日八股文7.1
  • Claude Code 全面指南:从安装到高效开发的实用教程
  • React安装使用教程
  • 「Java流程控制」do……while循环结构
  • 吸烟行为检测数据集介绍-2,108张图片 公共场所禁烟监控 健康行为研究
  • 【Java编程动手学】Java的“三体”世界:JVM、JRE、JDK的共生之道
  • CppCon 2018 学习:EMULATING THE NINTENDO 3DS
  • 手工部署与自动化部署场景模拟及参考项目
  • InnoDB索引
  • 胖喵安初 (azi) Android 应用初始化库 (类似 Termux)
  • android车载开发之HVAC
  • Redis-渐进式遍历
  • 算法-每日一题(DAY12)最长和谐子序列
  • 使用D435i运行ORB-SLAM3时,纯视觉模式与视觉-惯性模式的位姿矩阵定义问题探讨
  • CentOS系统新手指导手册