查看Ramda文档中的transduce,有两个示例,每个示例都会导致Typescript编译器引发不同的错误。
示例1:
test('ex. 1', () => {
const numbers = [1, 2, 3, 4]
const transducer = compose(
map(add(1)),
take(2)
)
const result = transduce(transducer, flip(append), [], numbers)
expect(result).toEqual([2, 3])
})
Typescript为flip(append)
引发以下异常:
Argument of type '(arg1: never[], arg0?: {} | undefined) => <T>(list: readonly T[]) => T[]' is not assignable to parameter of type '(acc: ({} | undefined)[], val: {} | undefined) => readonly ({} | undefined)[]'.
Types of parameters 'arg1' and 'acc' are incompatible.
Type '({} | undefined)[]' is not assignable to type 'never[]'.
Type '{} | undefined' is not assignable to type 'never'.
Type 'undefined' is not assignable to type 'never'.
如果将flip(append)
更改为flip(append) as any
,代码将按预期工作。
示例2:
test('ex. 2', () => {
const isOdd = x => x % 2 === 1
const firstOddTransducer = compose(
filter(isOdd),
take(1)
)
const result = transduce(
firstOddTransducer,
flip(append) as any,
[],
range(0, 100)
)
expect(result).toEqual([1])
})
Typescript为firstOddTransducer
引发以下异常:
Argument of type '(x0: readonly any[]) => Dictionary<any>' is not assignable to parameter of type '(arg: any[]) => readonly any[]'.
Type 'Dictionary<any>' is missing the following properties from type 'readonly any[]': length, concat, join, slice, and 16 more.
与上述相同,如果我将firstOddTransducer
更改为firstOddTransducer as any
,代码将按预期工作。
首先,这些特定错误甚至意味着什么?
其次,用功能性打字稿处理这类问题的最佳方法是什么?因此,经常在查看各种打字稿学习资源时,会警告用户不要使用any
或不要使用// @ts-ignore
,就像您永远不应该这样做一样,但是我的代码库变得越复杂,我的编程风格就越有用变得越来越多,我收到的关于完美可接受代码的更多无法理解的错误消息。我不介意花一些时间来改善类型,但是当我知道代码很好时,我不想花太多时间来调试类型问题。
[第三,当您不太确定类型或打字稿是否有问题(如上所述)或javascript代码是否有问题(例如,用于确定实际问题在哪里,以便您可以调查或忽略?
在撰写本文时,这是TypeScript的局限性,您根本无法表达必须从以后的使用中推断出类型的一部分。
直到调用transduce
才真正绑定所有类型参数,所以,直到那时它才是完整类型,或者相反,TypeScript在完成该操作之前不知道如何完成类型。 TypeScript会尝试从上下文推断类型,所以也许,如果将所有内容放在一行中,它也许可以做到这一点(不是说会做到)。
从根本上说,传感器是序列/流/可观察值的抽象,当您实际对某些数据运行传感器时,可以向编译器授予此信息。这时需要绑定数据的类型信息。
我唯一想到的是,您必须将unknown
用作数据的占位符类型,直到运行transduce
或into
。它不会授予您键入安全性,但是会抑制编译器警告,无论哪种方式都是误报。这不是完美的,但应该可以。