一边学技术一边学英语系列———Stirring Up (刺激起) Some TypeScript Magic(魔力)
 
Stirring Up 【刺激起】 Some TypeScript Magic【魔力】
原文地址:double-trouble.dev/post/typesc…
对于很多TypeScript的开发者来说,小的增强和辅助函数,可以明显的提高代码的可读性和可维护性。这篇博客致力于向你介绍5个必不可少的TypeScript技巧和辅助函数,目的在于易于复制粘贴到你的代码库中。
For TypeScript developers, small
enhancementsandhelperfunctions cansignificantlyimprove codereadabilityandmaintainability. This blog postis dedicated toproviding you with fiveessentialTypeScripttipsandhelperfunctions,designed tobe easilycopied and pastedinto yourcodebase.
开搞吧!
Let’s
dive in.
技巧一:使用空合并操作符(??)抛出内联异常
Inline Error Raising with
the Nullish Coalescing Operator
很多时候,我们发现自己需要抛出一个错误,如果一个特定的值为null或undefined。
Many times, we find ourselves needing to
throwan error if aparticularvalue is null or undefined.
TypeScript不需要手动检查,而是提供了一种使用空合并操作符(??)和一个简单的辅助函数来内联这个过程的方法。
Instead of checking this
manually, TypeScript provides a way toinlinethis process usingthe nullish coalescing operator(??) and a simple helper function.
const raise = (err: string) : never => { throw new Error(err);};
当这个'raise'函数与null合并运算符结合使用时,可以让你编写出可读性更强、更简洁的代码。
This ‘raise’ function, when
coupled withthe nullish coalescing operator, allows you to writemore readableandconcisecode.
const Page = (props: { params: { id?: string }}) => {
    const id = props.params.id ?? raise('No id provided');
};
因为这个令人惊讶的技巧,要向TypeScript布道者Matt Pocock和@HeyImMapleLeaf(最初发布)喊话,表示感谢。
Shout-outto theTypeScript Wizardhimself Matt Pocock and @HeyImMapleLeaf (originallyposted) for this amazing tip.
技巧二: 使用 映射类型
UtilizingMappedTypes
映射类型是TypeScript的一个强大 特性,它允许你基于 现有类型创建新类型。
Mapped Types is a
powerfulTypeScriptfeaturethat allows you to create new typesbased onexistingones.
它们可以帮助您保持类型不冗余(don't repeat youself),减少重复并提高可维护性。
They can help you to keep your types
DRY,reducing duplicationandimproving maintainability.
Readonly 只读的
映射类型的一个常见示例是Readonly。
A common example ofa Mapped Type is Readonly.
这使得T的所有属性都是只读的:
This makes all properties of T read-only:
interface IUser {
    name: string;
    age: number;
}
type ReadonlyUser = Readonly<IUser>;
现在ReadonlyUser的所有属性都是只读的。
Now,
all properties ofReadonlyUser areread-only.
Partial 部分属性
另一个方便的映射类型是Partial,它使T的所有属性都是可选的:
Another
handyMapped Type is Partial, which makes all properties of Toptional:
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 tocreate an object type where theproperty keysare K andthe property valuesare T:
type UserRecord = Record<string, IUser>;
UserRecord现在是一个对象类型,可以接受任何字符串作为键,但是值必须是 IUser类型。
UserRecord is now an object type that will accept
any stringas a key, and any valuemust be oftype IUser.
创建自己的映射类型 Creating Your Own Mapped Types
你可以不仅仅局限于TypeScript提供的映射类型。
You’re not just
limited tothe Mapped Types that TypeScript provides.
也可以创建自己的映射类型:
You can also
create your own:
type Nullable<T> = { [P in keyof T]: T[P] | null };
这个Nullable类型接受一个现有类型T,并产生一个新类型,其中每个属性都可为空。
This Nullable type
takesan existing type T, andproducesa new type where every property isnullable.
映射类型帮助您在现有类型的基础上创建复杂类型,减少代码重复并增强类型安全性。
Mapped types help you to create
complex typesbased on your existing ones,reducing code duplicationandenhancing type safety.
技巧三:Type Guarding 类型保护
TypeScript支持用户自定义类型保护来收缩 条件判断中对象的类型。
TypeScript supports
user-definedtype guards tonarrow downthe type of an objectwithin a conditional block.
这是通过使用返回布尔值的函数来实现的,布尔值指示对象是否属于 特定类型。
This is
achievedby using a function thatreturns a boolean,indicatingwhether the objectis ofaspecifictype.
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 guardthatensuresinputis treated as a stringwithinthe if block.
技巧四:Strongly-Typed Event Emitters 强类型事件发射器
在需要使用事件驱动 架构的场景下,可能需要使用事件发射器。
In cases where you need to use an
event-drivenarchitecture, you might need to use anevent emitter.
JavaScript内置事件发射器的缺点是它不是强类型的。
The
downsideof JavaScript’sbuilt-inevent emitter is that it’s notstrongly typed.
但不用担心,TypeScript正可以挽狂澜于既倒 扶大厦之将倾。
But
fear not, TypeScript is here tosave the day.
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 tocreate properties thatcan’t be changed after they’re set.
这对于创建具有不可改变的属性的对象特别有用。
This can be
particularlyuseful for creating objects with properties that shouldnever change.
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
attemptsto change the apiUrl or defaultTimeout willresult ina TypeScript error.
The End 结束语
这些只是TypeScript提供的特性和能力的几个例子,旨在 加快你的开发进度。
These are just
a few examplesof thefeaturesandtechniquesTypeScriptoffers toenhance yourdevelopment process.
有了这些技巧和辅助函数,您的代码将更干净、更安全、更易于维护。
With these tips and helper functions, your code will be
cleaner, safer, and easier to maintain.
转载自:https://juejin.cn/post/7279720525361790976




