Typescript 类型中的嵌套三元条件扩展
Nested ternary condition inside Typescript type extends
我正在从 JavaScript 开发过渡到强制 TypeScript 键入的雇主。我为包含典型 .on(event, handler)
.
的模型创建了一个 Interface
我的同事提出了一些我认为可以理解的代码,但它使用了这种嵌套的三元语句,这让人难以阅读。
interface Model {
...
on<T extends "added" | "failed" | "initialized" | "changed" | "removed"> (
event: T,
handler: T extends "changed" | "removed"
? (T extends "changed"
? (model: Model, entity: Entity, data: object) => void
: (model: Model, id: string) => void)
: (model: Model, entity: Entity) => void,
context?: object
): void
}
这似乎是一种根据传入 event
的参数为 handler
参数设置不同签名的方法。
它似乎有效,但我想知道是否有不同的模式来编写它,这样它更容易阅读和理解。
我会考虑使用映射接口并对其进行索引,因为在 TypeScript 中,对象类型自然会为您提供操作 "map a string literal to a particular type"。虽然您 可以 使用条件类型来做到这一点,但它往往更难阅读和维护。
作为重构的第一步,我会做这样的事情:
// use a mapping from event name to event handler type
interface EventHandlerMap {
added: (model: Model, entity: Entity) => void;
failed: (model: Model, entity: Entity) => void;
initialized: (model: Model, entity: Entity) => void;
changed: (model: Model, entity: Entity, data: object) => void;
removed: (model: Model, id: string) => void;
}
interface Model {
on<T extends keyof EventHandlerMap>(
event: T,
handler: EventHandlerMap[T], // index into the mapping
context?: object
): void;
}
您可以说服自己它的行为方式相同(或使用 link 到代码末尾查看)。 EventHandlerMap
接口只是一个助手,您实际上并未将其分配给任何对象。但它描述了从 Model.on()
的 event
类型 T
参数到 handler
参数的映射。我们使用 lookup types 将 handler
类型提取为 EventHandlerMap[T]
。
有可能进一步重构这个...例如,所有这些都是返回 void
并且第一个参数是 Model
的函数;也许您可以 EventHandlerMap
只跟踪不同事件之间的不同之处,然后使用更复杂的类型操作,但这可能比它的价值更麻烦。
好的,希望对您有所帮助;祝你好运!
我正在从 JavaScript 开发过渡到强制 TypeScript 键入的雇主。我为包含典型 .on(event, handler)
.
Interface
我的同事提出了一些我认为可以理解的代码,但它使用了这种嵌套的三元语句,这让人难以阅读。
interface Model {
...
on<T extends "added" | "failed" | "initialized" | "changed" | "removed"> (
event: T,
handler: T extends "changed" | "removed"
? (T extends "changed"
? (model: Model, entity: Entity, data: object) => void
: (model: Model, id: string) => void)
: (model: Model, entity: Entity) => void,
context?: object
): void
}
这似乎是一种根据传入 event
的参数为 handler
参数设置不同签名的方法。
它似乎有效,但我想知道是否有不同的模式来编写它,这样它更容易阅读和理解。
我会考虑使用映射接口并对其进行索引,因为在 TypeScript 中,对象类型自然会为您提供操作 "map a string literal to a particular type"。虽然您 可以 使用条件类型来做到这一点,但它往往更难阅读和维护。
作为重构的第一步,我会做这样的事情:
// use a mapping from event name to event handler type
interface EventHandlerMap {
added: (model: Model, entity: Entity) => void;
failed: (model: Model, entity: Entity) => void;
initialized: (model: Model, entity: Entity) => void;
changed: (model: Model, entity: Entity, data: object) => void;
removed: (model: Model, id: string) => void;
}
interface Model {
on<T extends keyof EventHandlerMap>(
event: T,
handler: EventHandlerMap[T], // index into the mapping
context?: object
): void;
}
您可以说服自己它的行为方式相同(或使用 link 到代码末尾查看)。 EventHandlerMap
接口只是一个助手,您实际上并未将其分配给任何对象。但它描述了从 Model.on()
的 event
类型 T
参数到 handler
参数的映射。我们使用 lookup types 将 handler
类型提取为 EventHandlerMap[T]
。
有可能进一步重构这个...例如,所有这些都是返回 void
并且第一个参数是 Model
的函数;也许您可以 EventHandlerMap
只跟踪不同事件之间的不同之处,然后使用更复杂的类型操作,但这可能比它的价值更麻烦。
好的,希望对您有所帮助;祝你好运!