typescript - 确定联合接口使用的接口
问题描述
假设我有以下内容:
interface StringOp {
(a: string, b: string): string;
}
interface NumberOp {
(a: number, b: number): number;
}
function doThing(callback: StringOp | NumberOp) {
if (callback is StringOp) {
callback("a", "b");
} else {
callback(1, 2);
}
}
我如何才能真正表达callback is StringOp
为类型检查?
我试图将上面的内容简化为 MWE,但下面更接近我的实际用例:
interface TickFunction<T> {
(val: T): void;
}
interface IndexedTickFunction<T> {
(val: T, index: number): void;
}
function forEachTick<T>(callback: TickFunction<T> | IndexedTickFunction<T>) {
...
}
如果可能的话,我想继续forEachTick
使用箭头符号文字进行调用:
forEachTick<SomeType>((v) => { ... })
或者forEachTick<SomeType>((v,i) => { ... })
.
解决方案
在 TS 中,接口仅在开发过程中存在,因此无法在运行时检查接口类型并进行操作。因此,您必须以某种方式在您的界面中包含一个“指示器”,以便在您创建回调方法时为其设置一些值。该指标可用于在运行时检查回调类型。TS 还提供了User-Defined Type Guards,因此最终的解决方案将如下所示:
interface StringOp {
opType: 'StringOp',
(a: string, b: string): string;
}
interface NumberOp {
opType: 'NumberOp',
(a: number, b: number): number;
}
function isStringOp(op: StringOp | NumberOp): op is StringOp {
return op.opType === 'StringOp';
}
function doThing(callback: StringOp | NumberOp) {
if (isStringOp(callback)) {
callback("a", "b");
} else {
callback(1, 2);
}
}
我根据更新的问题添加了另一个示例:
interface TickFunction<T> {
(val: T): void;
}
interface IndexedTickFunction<T> {
(val: T, index: number): void;
}
function isTickFn<T>(fn: TickFunction<T> | IndexedTickFunction<T>): fn is TickFunction<T> {
// in your example the indicator might be the function length
// because it indicates the number of arguments expected by the function
return fn.length === 1;
}
// I guess you also have to pass arguments to this function in order to pass them to your callback methods
function forEachTick<T>(callback: TickFunction<T> | IndexedTickFunction<T>, value: T, index?: number) {
if (isTickFn(callback)) {
callback(value);
} else {
callback(value, index);
}
}
for (let i=0; i<10; i++) {
forEachTick<string>((v: string) => console.log(v), 'some text');
}
for (let i=0; i<10; i++) {
forEachTick<boolean>((v: boolean, index: number) => console.log(v, index), true, i);
}
推荐阅读
- android - 如何从项目中删除 android 库并将其放入 Github
- c# - MVC c#LINQ OrderByDescending isnt'working
- r - 使用 dplyr 进行动态过滤
- django - 在django中一个接一个提交两个表单的问题
- return - 机器人框架得到结果
- odoo-13 - 如何在 Odoo 中处理每个销售订单中的采购订单?
- android - 保存当前 ImageView 状态以关闭和重新打开应用程序
- twitter-bootstrap - 在 bs timepicker 上应用自定义 CSS
- javascript - 在写入数据之前,Google 脚本循环检查重复项
- swiftui - SwiftUI 通过另一个视图实例设置状态变量