确定用于联合接口的接口
Determine the interface used for a union interface
假设我有以下内容:
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中,接口只存在于开发过程中,因此无法在运行时检查接口类型并执行smth。所以你必须以某种方式在你的接口中包含一个 "indicator" 以便在你创建你的回调方法时为它设置一些值。该指标可用于在运行时检查回调类型。 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);
}
假设我有以下内容:
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中,接口只存在于开发过程中,因此无法在运行时检查接口类型并执行smth。所以你必须以某种方式在你的接口中包含一个 "indicator" 以便在你创建你的回调方法时为它设置一些值。该指标可用于在运行时检查回调类型。 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);
}