TypeScript 无法推断出正确的类型
TypeScript doesn't infer correct type
对于这篇文章:
Promise.resolve('kromid')
.then(all(identity))
.then(([a]) => a.splita);
TypeScript 没有说明任何关于 a.splita
的内容。我预计它会失败:
Property 'splita' does not exist on type 'string'. Did you mean
'split'?
下面是代码的其余部分:
function all<T1, Param>(a1: Res<Param, T1>): (p: Param) => Promise<[T1]>;
function all<T1, T2, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>): (p: Param) => Promise<[T1, T2]>;
function all<T1, T2, T3, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>): (p: Param) => Promise<[T1, T2, T3]>;
function all<T1, T2, T3, T4, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>): (p: Param) => Promise<[T1, T2, T3, T4]>;
function all<T1, T2, T3, T4, T5, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>): (p: Param) => Promise<[T1, T2, T3, T4, T5]>;
function all<T1, T2, T3, T4, T5, T6, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6]>;
function all<T1, T2, T3, T4, T5, T6, T7, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>, a10: Res<Param, T10>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
function all<Param>(...values: Res<Param, any>[]): (p: Param) => Promise<any[]>;
function all<Param>(...values: Res<Param, any>[]): (p: Param) => Promise<any[]> {
return param => Promise.all(values.map(obj => obj.apply ? obj(param) : obj));
}
type Res<I, O> = ((i: I) => O | Promise<O>) | O | Promise<O>
function identity<T>(a: T): T {
return a;
}
你能找出问题所在吗?
感谢您指出我不太明白的问题。我确实更多地使用了您的代码,这是我的发现。类型推断不适用于 TypeScript 中的函数组合:
function identity<T>(a: T): T { return a; }
function toString<T>(a: T): string { return JSON.stringify(a); }
Promise.resolve('kromid')
.then(promiseValue => {
const composedFn = all(identity, toString);
// ^^^^^^^^^^
// T type of `promiseValue` was not inferred properly,
// and was replaces with `any`
return composedFn(promiseValue);
})
.then(([identityResult, toStringResult]) => {
})
请注意,类型推断对函数 (T) => T
无效,但对非泛型 return 类型的函数 (T) => string
有效。在路上,identityResult
是类型 any
,而 toStringResult
是正确的类型 string
。
我认为,真正的根本原因包含在这个 GitHub issue 中。抱歉,我的回答不是很有帮助。类型推断对我来说是最复杂的主题,这就是我深入研究您的示例的原因。
抓取我的旧答案
为什么会这样?
我认为,关键在于这一行:
.then(all(identity))
相当于
.then(x => all(identity)(x))
而不是
.then(x => all(identity(x)))
在两种情况下,类型的推断会有所不同,我认为您希望在获得前者的同时对代码进行后一种解释。
如何实现您期望看到的错误
变体 1:如果您重写代码以便 all()
以正确的顺序接收 string
承诺值和 identity()
,您会看到错误。
Promise.resolve('kromid')
.then(text => all(text)(identity))
.then(([a]) => a.splita);
导致:
[ts] Property 'splita' does not exist on type 'string'. Did you mean 'split'?
变体 2。重新排序重载的 all()
函数的参数,以便它能够以您想要的方式使用它:
function all<T1, Param>(p: Param): (a1: Res<Param, T1>) => Promise<[T1]>;
function all<T1, T2, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>) => Promise<[T1, T2]>;
function all<T1, T2, T3, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>) => Promise<[T1, T2, T3]>;
function all<T1, T2, T3, T4, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>) => Promise<[T1, T2, T3, T4]>;
function all<T1, T2, T3, T4, T5, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>) => Promise<[T1, T2, T3, T4, T5]>;
function all<T1, T2, T3, T4, T5, T6, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>) => Promise<[T1, T2, T3, T4, T5, T6]>;
function all<T1, T2, T3, T4, T5, T6, T7, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>) => Promise<[T1, T2, T3, T4, T5, T6, T7]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>, a10: Res<Param, T10>) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
function all<Param>(p: Param): (...values: Res<Param, any>[]) => Promise<any[]>;
function all<Param>(p: Param): (...values: Res<Param, any>[]) => Promise<any[]> {
return values => Promise.all(values.map((obj: any) => obj.apply ? obj(p) : obj));
}
type Res<I, O> = ((i: I) => O | Promise<O>) | O | Promise<O>;
function identity<T>(a: T): T {
return a;
}
Promise.resolve('kromid')
.then(all(identity))
.then(([a]) => a.splita);
它会达到相同的结果:
我希望,我的回答现在是完整和正确的。 :)
对于这篇文章:
Promise.resolve('kromid')
.then(all(identity))
.then(([a]) => a.splita);
TypeScript 没有说明任何关于 a.splita
的内容。我预计它会失败:
Property 'splita' does not exist on type 'string'. Did you mean 'split'?
下面是代码的其余部分:
function all<T1, Param>(a1: Res<Param, T1>): (p: Param) => Promise<[T1]>;
function all<T1, T2, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>): (p: Param) => Promise<[T1, T2]>;
function all<T1, T2, T3, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>): (p: Param) => Promise<[T1, T2, T3]>;
function all<T1, T2, T3, T4, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>): (p: Param) => Promise<[T1, T2, T3, T4]>;
function all<T1, T2, T3, T4, T5, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>): (p: Param) => Promise<[T1, T2, T3, T4, T5]>;
function all<T1, T2, T3, T4, T5, T6, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6]>;
function all<T1, T2, T3, T4, T5, T6, T7, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, Param>(a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>, a10: Res<Param, T10>): (p: Param) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
function all<Param>(...values: Res<Param, any>[]): (p: Param) => Promise<any[]>;
function all<Param>(...values: Res<Param, any>[]): (p: Param) => Promise<any[]> {
return param => Promise.all(values.map(obj => obj.apply ? obj(param) : obj));
}
type Res<I, O> = ((i: I) => O | Promise<O>) | O | Promise<O>
function identity<T>(a: T): T {
return a;
}
你能找出问题所在吗?
感谢您指出我不太明白的问题。我确实更多地使用了您的代码,这是我的发现。类型推断不适用于 TypeScript 中的函数组合:
function identity<T>(a: T): T { return a; }
function toString<T>(a: T): string { return JSON.stringify(a); }
Promise.resolve('kromid')
.then(promiseValue => {
const composedFn = all(identity, toString);
// ^^^^^^^^^^
// T type of `promiseValue` was not inferred properly,
// and was replaces with `any`
return composedFn(promiseValue);
})
.then(([identityResult, toStringResult]) => {
})
请注意,类型推断对函数 (T) => T
无效,但对非泛型 return 类型的函数 (T) => string
有效。在路上,identityResult
是类型 any
,而 toStringResult
是正确的类型 string
。
我认为,真正的根本原因包含在这个 GitHub issue 中。抱歉,我的回答不是很有帮助。类型推断对我来说是最复杂的主题,这就是我深入研究您的示例的原因。
抓取我的旧答案
为什么会这样?
我认为,关键在于这一行:
.then(all(identity))
相当于
.then(x => all(identity)(x))
而不是
.then(x => all(identity(x)))
在两种情况下,类型的推断会有所不同,我认为您希望在获得前者的同时对代码进行后一种解释。
如何实现您期望看到的错误
变体 1:如果您重写代码以便 all()
以正确的顺序接收 string
承诺值和 identity()
,您会看到错误。
Promise.resolve('kromid')
.then(text => all(text)(identity))
.then(([a]) => a.splita);
导致:
[ts] Property 'splita' does not exist on type 'string'. Did you mean 'split'?
变体 2。重新排序重载的 all()
函数的参数,以便它能够以您想要的方式使用它:
function all<T1, Param>(p: Param): (a1: Res<Param, T1>) => Promise<[T1]>;
function all<T1, T2, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>) => Promise<[T1, T2]>;
function all<T1, T2, T3, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>) => Promise<[T1, T2, T3]>;
function all<T1, T2, T3, T4, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>) => Promise<[T1, T2, T3, T4]>;
function all<T1, T2, T3, T4, T5, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>) => Promise<[T1, T2, T3, T4, T5]>;
function all<T1, T2, T3, T4, T5, T6, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>) => Promise<[T1, T2, T3, T4, T5, T6]>;
function all<T1, T2, T3, T4, T5, T6, T7, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>) => Promise<[T1, T2, T3, T4, T5, T6, T7]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
function all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, Param>(p: Param): (a1: Res<Param, T1>, a2: Res<Param, T2>, a3: Res<Param, T3>, a4: Res<Param, T4>, a5: Res<Param, T5>, a6: Res<Param, T6>, a7: Res<Param, T7>, a8: Res<Param, T8>, a9: Res<Param, T9>, a10: Res<Param, T10>) => Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
function all<Param>(p: Param): (...values: Res<Param, any>[]) => Promise<any[]>;
function all<Param>(p: Param): (...values: Res<Param, any>[]) => Promise<any[]> {
return values => Promise.all(values.map((obj: any) => obj.apply ? obj(p) : obj));
}
type Res<I, O> = ((i: I) => O | Promise<O>) | O | Promise<O>;
function identity<T>(a: T): T {
return a;
}
Promise.resolve('kromid')
.then(all(identity))
.then(([a]) => a.splita);
它会达到相同的结果:
我希望,我的回答现在是完整和正确的。 :)