条件类型 ReturnType 函数签名重载解析
Conditional types ReturnType function signature overload resolution
我正在尝试使用 typescript 2.8 的新 conditional types,(尚未发布版本 2.8.0-dev.20180307)我不知道这是错误还是误用.我的重点是我对 MockedImplementation<F>
的声明,它可以是匹配 F
的完整函数,F
的 return 类型,如果 return 类型的 F
是一个 Promise
,那么它也可能是 promise 解析的内容——所有内容都将相应地由 mockIt()
.
包装
type MockedImplementation<F> =
F | // The function signature
((ReturnType<F extends (...args: any[]) => any ? F : any>) extends infer T
? T extends Promise<infer R>
? (T | R) // Or the promise or just the type that the promise resolves to
: T // or whatever type this is
: never);
interface Wrapped<T> {
result: T
}
function mockIt<F>(pretend : MockedImplementation<F>) : F {
throw new Error('Not Implemented'); // doesn't matter
}
interface SomeOperationA {
(parameters : { 'a': number[], 'b'?: string }) : Promise<string>;
}
mockIt<SomeOperationA>(() => Promise.resolve('hello')); // OK
mockIt<SomeOperationA>(Promise.resolve('hello')); // OK
mockIt<SomeOperationA>('hello'); // OK
mockIt<SomeOperationA>(42); // Type error.
mockIt
of SomeOperationA
有效,可能直接是因为没有函数签名覆盖。但是 SomeOperationB
的 mockIt
失败了:
interface SomeOperationB {
(parameters : { 'a': number[], 'b'?: string }) : Promise<string>;
(parameters : { 'a': number[], 'b'?: string }, rawResponse : true) : Promise<Wrapped<string>>;
(parameters : { 'a': number[], 'b'?: string }, rawResponse : false) : Promise<string>;
}
mockIt<SomeOperationB>(() => Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped<string>'.
mockIt<SomeOperationB>(Promise.resolve('hello')); // OK
mockIt<SomeOperationB>('hello'); // OK
mockIt<SomeOperationB>(42); // Type error.
似乎是交叉类型而不是联合类型?但我敢肯定它比那更细微。
我在某处看到一条关于“考虑最后一个重载,因为它可能是最普遍的重载”的注释,但我认为它在这里不相关,因为它的行为似乎并不重要。
编辑
@jcalz 说的有道理:
interface SomeOperationB {
(wrapped : true) : Promise<Wrapped<string>>;
(wrapped : false) : Promise<string>;
}
interface Wrapped<T> { result: T }
declare function acceptSomeOperationB(x: SomeOperationB): void;
acceptSomeOperationB(() => Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped<string>'.
acceptSomeOperationB(() => Promise.resolve({ result: 'hello' })); // ❌ Type '{ result: string; }' is not assignable to type 'string'.
没有条件类型的问题的较小再现:
declare function acceptSomeOperationB(x: SomeOperationB): void;
acceptSomeOperationB(() => Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped<string>'.
很明显,TypeScript 不认为箭头函数与 SomeOperationB
兼容,因为它无法满足其中一个重载签名。实际上,如果您将 true
作为第二个参数传递给该函数,它将 而不是 return 和 Promise<Wrapped<string>>
,这是第二个签名所要求的SomeOperationB
。
一旦你决定了如何解决这个问题,它就应该开始工作了(或者你至少可以继续处理条件类型的问题。)
祝你好运。
我正在尝试使用 typescript 2.8 的新 conditional types,(尚未发布版本 2.8.0-dev.20180307)我不知道这是错误还是误用.我的重点是我对 MockedImplementation<F>
的声明,它可以是匹配 F
的完整函数,F
的 return 类型,如果 return 类型的 F
是一个 Promise
,那么它也可能是 promise 解析的内容——所有内容都将相应地由 mockIt()
.
type MockedImplementation<F> =
F | // The function signature
((ReturnType<F extends (...args: any[]) => any ? F : any>) extends infer T
? T extends Promise<infer R>
? (T | R) // Or the promise or just the type that the promise resolves to
: T // or whatever type this is
: never);
interface Wrapped<T> {
result: T
}
function mockIt<F>(pretend : MockedImplementation<F>) : F {
throw new Error('Not Implemented'); // doesn't matter
}
interface SomeOperationA {
(parameters : { 'a': number[], 'b'?: string }) : Promise<string>;
}
mockIt<SomeOperationA>(() => Promise.resolve('hello')); // OK
mockIt<SomeOperationA>(Promise.resolve('hello')); // OK
mockIt<SomeOperationA>('hello'); // OK
mockIt<SomeOperationA>(42); // Type error.
mockIt
of SomeOperationA
有效,可能直接是因为没有函数签名覆盖。但是 SomeOperationB
的 mockIt
失败了:
interface SomeOperationB {
(parameters : { 'a': number[], 'b'?: string }) : Promise<string>;
(parameters : { 'a': number[], 'b'?: string }, rawResponse : true) : Promise<Wrapped<string>>;
(parameters : { 'a': number[], 'b'?: string }, rawResponse : false) : Promise<string>;
}
mockIt<SomeOperationB>(() => Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped<string>'.
mockIt<SomeOperationB>(Promise.resolve('hello')); // OK
mockIt<SomeOperationB>('hello'); // OK
mockIt<SomeOperationB>(42); // Type error.
似乎是交叉类型而不是联合类型?但我敢肯定它比那更细微。
我在某处看到一条关于“考虑最后一个重载,因为它可能是最普遍的重载”的注释,但我认为它在这里不相关,因为它的行为似乎并不重要。
编辑
@jcalz 说的有道理:
interface SomeOperationB {
(wrapped : true) : Promise<Wrapped<string>>;
(wrapped : false) : Promise<string>;
}
interface Wrapped<T> { result: T }
declare function acceptSomeOperationB(x: SomeOperationB): void;
acceptSomeOperationB(() => Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped<string>'.
acceptSomeOperationB(() => Promise.resolve({ result: 'hello' })); // ❌ Type '{ result: string; }' is not assignable to type 'string'.
没有条件类型的问题的较小再现:
declare function acceptSomeOperationB(x: SomeOperationB): void;
acceptSomeOperationB(() => Promise.resolve('hello')); // ❌ Type 'string' is not assignable to type 'Wrapped<string>'.
很明显,TypeScript 不认为箭头函数与 SomeOperationB
兼容,因为它无法满足其中一个重载签名。实际上,如果您将 true
作为第二个参数传递给该函数,它将 而不是 return 和 Promise<Wrapped<string>>
,这是第二个签名所要求的SomeOperationB
。
一旦你决定了如何解决这个问题,它就应该开始工作了(或者你至少可以继续处理条件类型的问题。)
祝你好运。