我希望有人可以帮助识别我在下面的类型中遗漏的内容。我创建了一个名为match
的函数,它接受一个元组数组
在识别时,将执行匹配功能。例如:
type Fn1<A, B> = (a: A, ...rest: empty[]) => B;
declare export function match<A>(
xs: Array<[Class<A>, (x: A) => mixed]>,
...rest: empty[]
): Fn1<A, mixed>;
describe('match', () => {
class FileExists {}
class FileDoesNotExist {}
let matcher: (x: FileExists | FileDoesNotExist) => mixed;
beforeEach(() => {
const whenFileExists = [FileExists, (x: FileExists) => x];
const whenFileDoesNotExist = [FileDoesNotExist, (x: FileDoesNotExist) => x];
matcher = match([whenFileExists, whenFileDoesNotExist]);
});
it('should return an instance of whenFileDoesNotExist', () => {
// Should invoke the function in the tuple containing the FileDoesNotExist class
expect(matcher(new FileDoesNotExist()) instanceof FileDoesNotExist).toBe(true);
});
});
问题似乎是这些类型正在统一。我收到以下错误:
1406: let matcher: (x: FileExists | FileDoesNotExist) => mixed;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileDoesNotExist. This type is incompatible with the expected param type of
1409: const whenFileExists = [FileExists, (x: FileExists) => x];
^^^^^^^^^^ FileExists
test/fp.test.js:1406
1406: let matcher: (x: FileExists | FileDoesNotExist) => mixed;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileExists. This type is incompatible with the expected param type of
1412: (x: FileDoesNotExist) => x
^^^^^^^^^^^^^^^^ FileDoesNotExist
test/fp.test.js:1409
1409: const whenFileExists = [FileExists, (x: FileExists) => x];
^^^^^^^^^^ FileExists. This type is incompatible with the expected param type of
1412: (x: FileDoesNotExist) => x
^^^^^^^^^^^^^^^^ FileDoesNotExist
test/fp.test.js:1409
1409: const whenFileExists = [FileExists, (x: FileExists) => x];
^ FileExists. This type is incompatible with the expected param type of
1412: (x: FileDoesNotExist) => x
^^^^^^^^^^^^^^^^ FileDoesNotExist
test/fp.test.js:1411
1411: FileDoesNotExist,
^^^^^^^^^^^^^^^^ FileDoesNotExist. This type is incompatible with the expected param type of
1409: const whenFileExists = [FileExists, (x: FileExists) => x];
^^^^^^^^^^ FileExists
test/fp.test.js:1412
1412: (x: FileDoesNotExist) => x
^ FileDoesNotExist. This type is incompatible with the expected param type of
1409: const whenFileExists = [FileExists, (x: FileExists) => x];
^^^^^^^^^^ FileExists
我无法弄清楚我在这里缺少什么。有没有人看到我遗漏或遗忘的东西?
答案 0 :(得分:0)
类型变量func createDate(stringDate: String) -> Date {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy.MM.dd"
return formatter.date(from: stringDate)!
}
func sumAmounts(_ data: [Item]) -> [Item] {
var dict = [Double: Double]()
data.forEach { item in
let key = item.date.timeIntervalSince1970
var amount = dict[key] ?? 0
amount += item.amount
dict[key] = amount
}
var newData = [Item]()
for (key, val) in dict {
newData.append(Item(date: Date.init(timeIntervalSince1970: key), amount: val))
}
return newData
}
必须在A
内使用的任何位置解析为相同的类型,这会导致问题。
如果删除参数并尝试执行Flow尝试执行的操作,则会遇到同样的问题。您希望类型match
是最常见的情况(我称之为A
):
Existence
但这不起作用,因为type Existence = FileExists | FileDoesNotExist
declare export function match(
xs: Array<[Class<Existence>, (x: Existence) => mixed]>,
...rest: empty[]
): Fn1<Existence, mixed>;
不是一个类,所以Existence
没有任何意义。
您需要Class<Existence>
中的A
对于数组的每个元素都不同,这是不可能的。相反,您可以使用通配符类型(有时称为存在量化类型),由Class<A>
表示:
*
此处,declare export function match<A>(
xs: Array<[Class<*>, (x: A) => mixed]>,
...rest: empty[]
): Fn1<*, mixed>;
将被解析为A
,但在使用FileExists | FileDoesNotExist
的每个地方,可以推断为*
或{{1}根据用法。
除了在this blogpost之外,我没有记录在任何地方,所以我对它的语义并不是100%肯定。可能需要花一点时间才能完全正确使用。
答案 1 :(得分:0)
存在主义类型是个好主意,但它的问题在于它在应该的时候没有发现错误。例如,如果我执行以下操作:
declare export function match<A>(
xs: Array<[Class<*>, (x: A) => mixed]>,
...rest: empty[]
): Fn1<*, mixed>;
const whenFileExists = [FileExists, (x: FileExists) => x];
const whenFileDoesNotExist = [FileDoesNotExist, (x: string) => x];
matcher = fp.match([whenFileExists, whenFileDoesNotExist]);
(matcher(new FileDoesNotExist()): mixed);
我们应该在将x
指定为string
时收到错误,因为它应该是FileDoesNotExist
的实例。但是,流程不会捕获此错误。事实证明,有一种方法可以以为每个案例添加声明为代价来完成这项工作。这意味着有两个条目的情况下的声明,以及有三个条目时的单独声明。需要为n
条目做出声明:
declare export function match<A, B>(
xs: [[Class<A>, (x: A) => mixed], [Class<B>, (x: B) => mixed]],
...rest: empty[]
): (x: A | B) => mixed;
declare export function match<A, B, C>(
xs: [[Class<A>, (x: A) => mixed], [Class<B>, (x: B) => mixed], [Class<C>, (x: C) => mixed]],
...rest: empty[]
): (x: A | B | C) => mixed;
虽然为每个案例写出一份声明是很痛苦的,但在大多数情况下,不太可能有超过5个项目要匹配。我应该能够安全地添加最多5个条目的声明。转到上面的代码片段,这将捕获x作为字符串并抛出以下错误:
This type is incompatible with the expected param type of
string: test.js:xx
如果流程能够使用存在类型推断出这将是很好的。