我正在尝试创建Set的子类,因为我不能简单地从它扩展,我正在包装它的功能。
我正在尝试实现Symbol.iterator方法,但Flow没有。
这是我的代码:
/* @flow */
class CSet<T> {
_set: Set<T>;
[Symbol.iterator](): Iterator<T> {
return this._set[Symbol.iterator];
}
}
var a: CSet = new CSet();
for(var b of a){
}
core.js:309:5,29: property @@iterator
Property not found in
test.js:2:7,10: CSet
test.js:4:2,6:2:
computed property keys not supported
第二个错误不是很大的交易,因为我可以轻易地压制它。我想知道我是不是一起做错了什么。
答案 0 :(得分:5)
因为Flow目前没有对符号的一般支持,所以它代表Symbol.iterator
的方式是hacky并且基本上阻止了在用户空间中定义迭代器的能力(它的支持仅适用于库定义):( < / p>
特别是Flow期望一个iterable上有一个@@iterator
属性(肯定不是一个有效的属性名称 - 但这是获得库定义支持的暂时黑客攻击)。
因此,在获得正确的符号支持之前,最好的解决方法是为此模块创建一个库定义,使用此@@iterator
属性来理解Flow:
// RealModule.js
export class CSet {
[Symbol.iterator]() {
return this._set[Symbol.iterator];
}
}
// RealModule.FlowLibDef.js
declare module RealModule {
declare class CSet<T> {
_set: Set<T>;
@@iterator(): Iterator<T>;
}
}
答案 1 :(得分:3)
// @flow
class MyCollection<T> {
/*:: @@iterator(): Iterator<T> { return ({}: any); } */
// $FlowFixMe: computed property
[Symbol.iterator](): Iterator<T> {
// NOTE: this could just as easily return a different implementation
return new MyIterator(this);
}
}
class MyIterator<+T> {
/*:: @@iterator(): Iterator<T> { return (this: any); } */
// $FlowFixMe: computed property
[Symbol.iterator](): Iterator<T> {
return this;
}
next(): IteratorResult<T, void> {
return { done: false, value: someT };
// or return { done: true, value: undefined };
}
}
for (const value of new MyCollection()) {
console.log(value);
}
这个工作的原因是flow解释/*:: code */
,好像它是源代码中的流代码,除了它在运行时被注释掉,因此实际上不会影响代码。
Flow本质上知道@@iterator
方法,尽管它不是有效的JavaScript,因此我们将其定义为现有,返回Iterator<T>
,并返回一个适用于它的值(即空对象)施放为any
)。
然后,flow会完全忽略计算属性方法,就好像它根本没有定义一样。实际上从方法中返回有效的Iterator<T>
是至关重要的,否则事情会在运行时中断。
答案 2 :(得分:1)
我发现了一个技巧,可以让用户定义的类标记为可迭代,而无需为整个类编写和维护并行的libdef。
关键是编写一个实现[Symbol.iterator]()
的专用超类,并为该超类提供一个libdef:
// IterableBase.js
export default class IterableBase {
[Symbol.iterator]() {
return this._Symbol_iterator();
}
}
// IterableBase.js.flow
// @flow
declare class IterableBase<T> {
@@iterator(): Iterator<T>;
}
export default IterableBase;
现在,您可以让自定义类扩展IterableBase
并实现替换方法名称:
// RealModule.js
// @flow
import IterableBase from './IterableBase';
class CSet<T> extends IterableBase<T> {
_Symbol_iterator(): Iterator<T> {
...
}
}
这显然仍然是一个黑客,但它应该比替代方案更容易和更安全。
答案 3 :(得分:0)
试试这个javascript代码
// module -- start
let map = new WeakMap();
class Foo {
constructor(any) {
map.set(this, new Set(any));
}
values() {
return map.get(this).values();
}
[Symbol.iterator]() {
return this.values();
}
}
// module -- end
for(let item of new Foo([1,2,3])) {
console.log(item);
}
见