簡體   English   中英

如何防止Flowtype統一類型?

[英]How to prevent Flowtype from unifying types?

我希望有人可以幫助我找到我在下面的類型中遺漏的東西。 我創建了一個名為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

我無法弄清楚我在這里缺少什么。 有沒有人看到我要遺忘或忘記的事情?

類型變量A必須在match使用的任何地方解析為相同類型,這導致問題。

如果刪除參數並嘗試執行Flow嘗試執行的操作,則會遇到同樣的問題。 你希望類型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 in Class<A> ,這是不可能的。 相反,您可以使用通配符類型(有時稱為存在量化類型),用*表示:

declare export function match<A>(
  xs: Array<[Class<*>, (x: A) => mixed]>,
  ...rest: empty[]
): Fn1<*, mixed>;

這里, A將被解析為FileExists | FileDoesNotExist FileExists | FileDoesNotExist ,但每個地方使用* ,根據用途可以推斷為FileExistsFileDoesNotExist

除了在這篇博文中 ,我沒有記錄到任何我能找到的地方,所以我對它的語義並不是100%肯定。 使用完全正確可能需要一點點小費。

存在主義類型是一個很好的想法,但它的問題在於它在應該的時候沒有發現錯誤。 例如,如果我執行以下操作:

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

如果流程能夠使用存在類型推斷出這將是很好的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM