链接:https://medium.com/@technicadil_001/how-to-write-better-types...
作者:Debabrata Dash
原标题:How to write better Typescript codes?
在本文中,我们将讨论大约 15 个编写更好的 Typescript 代码的技巧。
译者:本文讨论了 15 个实用技巧,以帮助开发者编写更好的 TypeScript 代码。这些技巧包括可选链接、映射类型、实用类型等,旨在提高代码的安全性、可读性和功能性。通过这些技巧,开发者可以更有效地管理数据类型,从而构建更稳健的应用程序。
1 可选链 (?.):
通过可选的链接,您可以安全地访问嵌套的属性或方法,而无需担心 null 值或未定义的值。如果任何中间属性为 null 或未定义,它就会短路评估。
const user = {
name: 'Piotr',
address: {
city: 'Warsaw',
postalCode: '00-240'
}
};
const postalCode = user.address?.postalCode;
console.log(postalCode); // 00-240
const invalidCode = user.address?.postalCode?.toLowerCase();
console.log(invalidCode); // Output: undefined
2 使用映射类型进行转换
映射类型允许您通过转换现有类型的属性来创建新类型。
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
type Partial<T> = {
[P in keyof T]?: T[P];
};
3 善用实用程序类型
TypeScript 提供了多种实用程序类型来帮助进行常见的类型转换。
i)Partial<T>
:使所有属性成为可选属性。
ii) Required<T>
: 使所有属性成为必需属性。
iii) Readonly<T>
: 将所有属性设置为只读。
iv) Record<K, T>
: 使用类型为 T 的键 K 创建一个类型。
type Person = {
name: string;
age: number;
};
type PartialPerson = Partial<Person>;
type ReadonlyPerson = Readonly<Person>;
4 类型防护
使用 Type Guards 缩小条件块中的类型范围
function isString(value: unknown): value is string {
return typeof value === 'string';
}
5 模板文字类型
Tese 允许您通过组合字符串文字来创建新的字符串类型。
type EventName = 'click' | 'hover';
type EventHandlerName = `${EventName}Handler`; // 'clickHandler' | 'hoverHandler'
6 使用索引访问类型
使用索引访问类型来提取属性的类型。
type Person = { name: string; age: number };
type NameType = Person['name']; // string
7 将映射类型中的键重新映射
创建新类型时,转换键。
type PrefixKeys<T, P extends string> = {
[K in keyof T as `${P}${K & string}`]: T[K]
};
type PrefixedPerson = PrefixKeys<{ name: string; age: number }, 'prefix_'>;
// { prefix_name: string; prefix_age: number }
8 Discriminated 联合类型
这些可以帮助您创建不同类型的类型安全联合。
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'square'; side: number };
function getArea(shape: Shape) {
switch (shape.kind) {
case 'circle': return Math.PI * shape.radius ** 2;
case 'square': return shape.side ** 2;
}
}
9 泛型中的类型推断
利用 ‘infer’ 提取并使用条件类型中的类型。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
type Fn = () => number;
type Result = ReturnType<Fn>; // number
10 模块增强
使用新功能扩展现有模块。
// augmentations.ts
import 'express';
declare module 'express' {
interface Request {
user?: { id: string; role: string };
}
}
11 声明合并的interface
合并 interface 以扩展类型,对于第三方库尤其有用。
interface Window {
myCustomProperty: string;
}
window.myCustomProperty = 'Hello!';
12 函数重载
提供多个函数签名以更好地进行类型检查。
function createDate(timestamp: number): Date;
function createDate(year: number, month: number, day: number): Date;
function createDate(x: number, y?: number, z?: number): Date {
return y !== undefined && z !== undefined ? new Date(x, y, z) : new Date(x);
}
13 Branded 类型
使用 Branded 类型来创建名义类型。
type UserId = string & { _brand: 'UserId' };
function createUserId(id: string): UserId {
return id as UserId;
}
14 具有条件类型的模板文字类型
将模板文字类型与条件类型相结合以进行高级字符串操作。
type ExtractRouteParams<T extends string> = T extends `/${infer Param}/${infer Rest}`
? { param: Param } & ExtractRouteParams<`/${Rest}`>
: {};
type Params = ExtractRouteParams<'/user/:id/posts/:postId'>;
// { param: 'user' } & { param: 'posts' }
15 可变参数元组类型
Typescript 4+ 支持可变元组类型,允许元组捕获数组的其余部分。
type Push<T extends any[], V> = [...T, V];
type Result = Push<[1, 2, 3], 4>; // [1, 2, 3, 4]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。