Stirring Up 【刺激起】 Some TypeScript Magic【魔力】
原文地址:double-trouble.dev/post/typesc...
对于很多TypeScript的开发者来说,小的增强
和辅助
函数,可以明显的
提高代码的可读性
和可维护性
。这篇博客致力于
向你介绍5个必不可少
的TypeScript技巧
和辅助
函数,目的
在于易于复制粘贴
到你的代码库
中。
For TypeScript developers, small
enhancements
andhelper
functions cansignificantly
improve codereadability
andmaintainability
. This blog postis dedicated to
providing you with fiveessential
TypeScripttips
andhelper
functions,designed to
be easilycopied and pasted
into yourcodebase
.
开搞
吧!
Let's
dive in
.
技巧一:使用空合并操作符(??)
抛出内联异常
Inline Error Raising with
the Nullish Coalescing Operator
很多时候,我们发现自己需要抛出
一个错误,如果一个特定
的值为null或undefined。
Many times, we find ourselves needing to
throw
an error if aparticular
value is null or undefined.
TypeScript不需要手动
检查,而是提供了一种使用空合并操作符
(??)和一个简单的辅助函数来内联
这个过程的方法。
Instead of checking this
manually
, TypeScript provides a way toinline
this process usingthe nullish coalescing operator
(??) and a simple helper function.
ts
const raise = (err: string) : never => { throw new Error(err);};
当这个'raise'函数与null合并
运算符结合使用时,可以让你编写出可读性更强
、更简洁
的代码。
This 'raise' function, when
coupled with
the nullish coalescing operator, allows you to writemore readable
andconcise
code.
ts
const Page = (props: { params: { id?: string }}) => {
const id = props.params.id ?? raise('No id provided');
};
因为这个令人惊讶的技巧,要向TypeScript布道者
Matt Pocock和@HeyImMapleLeaf(最初
发布)喊话,表示感谢。
Shout-out
to theTypeScript Wizard
himself Matt Pocock and @HeyImMapleLeaf (originally
posted) for this amazing tip.
技巧二: 使用
映射
类型
Utilizing
Mapped
Types
映射类型是TypeScript的一个强大
特性
,它允许你基于
现有
类型创建新类型。
Mapped Types is a
powerful
TypeScriptfeature
that allows you to create new typesbased on
existing
ones.
它们可以帮助您保持类型不冗余(don't repeat youself)
,减少重复
并提高可维护性
。
They can help you to keep your types
DRY
,reducing duplication
andimproving maintainability
.
Readonly 只读的
映射类型的一个常见示例
是Readonly。
A common example of
a Mapped Type is Readonly.
这使得T的所有属性都是只读的:
This makes all properties of T read-only:
ts
interface IUser {
name: string;
age: number;
}
type ReadonlyUser = Readonly<IUser>;
现在ReadonlyUser的所有属性
都是只读的
。
Now,
all properties of
ReadonlyUser areread-only
.
Partial 部分属性
另一个方便的
映射类型是Partial,它使T的所有属性都是可选的
:
Another
handy
Mapped Type is Partial, which makes all properties of Toptional
:
ts
interface IUser {
name: string;
age: number;
}
type PartialUser = Partial<IUser>;
// PartialUser类型:
{
name?: string,
age?: number
}
Record 记录
Record<K,T> Mapped Type可以用来
创建一个属性键
为K,属性值
为T的对象类型:
The Record<K,T> Mapped Type can
be used to
create an object type where theproperty keys
are K andthe property values
are T:
ts
type UserRecord = Record<string, IUser>;
UserRecord现在是一个对象类型,可以接受任何字符串
作为键,但是值必须是
IUser类型
。
UserRecord is now an object type that will accept
any string
as a key, and any valuemust be of
type IUser
.
创建自己的映射类型 Creating Your Own Mapped Types
你可以不仅仅局限于
TypeScript提供的映射类型。
You're not just
limited to
the Mapped Types that TypeScript provides.
也可以创建自己的
映射类型:
You can also
create your own
:
ts
type Nullable<T> = { [P in keyof T]: T[P] | null };
这个Nullable类型接受
一个现有类型T,并产生
一个新类型,其中每个属性都可为空
。
This Nullable type
takes
an existing type T, andproduces
a new type where every property isnullable
.
映射类型帮助您在现有类型的基础上创建复杂类型
,减少代码重复
并增强类型安全性
。
Mapped types help you to create
complex types
based on your existing ones,reducing code duplication
andenhancing type safety
.
技巧三:Type Guarding 类型保护
TypeScript支持用户自定义
类型保护来收缩
条件判断中
对象的类型。
TypeScript supports
user-defined
type guards tonarrow down
the type of an objectwithin a conditional block
.
这是通过使用返回布尔值
的函数来实现
的,布尔值指示
对象是否属于
特定
类型。
This is
achieved
by using a function thatreturns a boolean
,indicating
whether the objectis of
aspecific
type.
ts
function isString(test: any): test is string {
return typeof test === "string";
}
function printLength(input: string | any[]) {
if (isString(input)) {
console.log(input.length);
} else {
console.log(input.length);
}
}
在本例中,isString函数是一个类型保护
,确保
在if判断
中将输入作为字符串处理
。
In this example, isString is a
type guard
thatensures
inputis treated as a string
withinthe if block
.
技巧四:Strongly-Typed Event Emitters 强类型事件发射器
在需要使用事件驱动
架构
的场景下,可能需要使用事件发射器
。
In cases where you need to use an
event-driven
architecture
, you might need to use anevent emitter
.
JavaScript内置
事件发射器的缺点
是它不是强类型
的。
The
downside
of JavaScript'sbuilt-in
event emitter is that it's notstrongly typed
.
但不用担心
,TypeScript正可以挽狂澜于既倒 扶大厦之将倾
。
But
fear not
, TypeScript is here tosave the day
.
ts
import { EventEmitter } from "events";
interface MyEvents {
event1: (param1: string, param2: number) => void;
event2: () => void;
}
class MyEventEmitter extends EventEmitter {
public emit<T extends keyof MyEvents>(event: T,...args: Parameters<MyEvents[T]>) {
return super.emit(event, ...args);
}
public on<T extends keyof MyEvents>(event: T, listener: MyEvents[T]): this {
return super.on(event, listener);
}
}
const myEmitter = new MyEventEmitter();
myEmitter.on('event1', (param1, param2) => {
// 类型安全的参数!
// Type-safe parameters!
});
有了这段代码,您就可以使用完全类型安全
的事件发射器了! With this code, you can enjoy a fully type-safe
event emitter!
技巧五 Enforcing Readonly Properties 强制执行只读属性
TypeScript有readonly修饰符
,可以很容易地
创建那些设置好后就不能修改
的属性。
TypeScript has the readonly
modifier
,making it easy to
create properties thatcan't be changed after they're set
.
这对于创建具有不可改变
的属性的对象特别
有用。
This can be
particularly
useful for creating objects with properties that shouldnever change
.
ts
interface Config {
readonly apiUrl: string;
readonly defaultTimeout: number;
}
const config: Config = {
apiUrl: "https://myapi.com",
defaultTimeout: 5000,
};
config.apiUrl = "https://anotherapi.com";
// 错误!
// Error!
在这个例子中,任何改变apiUrl或defaultTimeout的尝试
都会导致
TypeScript报错。
In this example, any
attempts
to change the apiUrl or defaultTimeout willresult in
a TypeScript error.
The End 结束语
这些只是TypeScript提供的特性
和能力
的几个例子
,旨在
加快你的开发进度
。
These are just
a few examples
of thefeatures
andtechniques
TypeScriptoffers to
enhance yourdevelopment process
.
有了这些技巧和辅助函数,您的代码将更干净、更安全、更易于维护
。
With these tips and helper functions, your code will be
cleaner, safer, and easier to maintain
.