Description
TypeScript Version: 3.7.3
The typescript.SymbolTable
is like an ES6 Map
-- typescript.d.ts describes it as 'based on the ES6 Map interface'.
However, the underlying interface typescript.UnderscoreEscapedMap
does not implement the Map
interface, or the Iterable
, or Iterator
protocols. This means it's not possible to iterate over properly without shim code, which varies from manually implementing the Iterator protocol (annoying!) to overriding the type with as Map<ts.__String, ts.Symbol>
(bad!).
Code Example
import * as ts from "typescript";
const p = ts.createProgram(["t.d.ts"], {});
const c = p.getTypeChecker();
p.getSourceFiles().map(f => {
f.forEachChild(n => {
if (!ts.isModuleDeclaration(n)) return;
const s = c.getSymbolAtLocation(n.name);
if (!s) return;
const scanMembers = (s: ts.Symbol) => {
if (s.valueDeclaration === undefined)
console.log("missing valueDeclaration on", s.getName());
type m = Iterator<any>
if (!s.exports) return;
if (!(Symbol.iterator in s.exports))
return console.log("not iterable", s.getName())
for (let [/*name*/, member] of (s.exports as Map<ts.__String, ts.Symbol>)) {
scanMembers(member);
}
}
scanMembers(s);
})
})
typescript.UnderscoreEscapedMap
is not recognized as a Map
due to clear()
, delete()
, set()
, [Symbol.toStringTag]
and [Symbol.iterator]
being undefined.
Testing map assertion
// Type 'ReadonlyUnderscoreEscapedMap<any>' is missing the following properties
// from type 'Map<any, any>': clear, delete, set, [Symbol.iterator],
// [Symbol.toStringTag] ts(2739)
const x: Map<any, any> = void 0 as any as ts.ReadonlyUnderscoreEscapedMap<any>
Perhaps this is a compiler internals issue, as using as Map<ts.__String, ts.Symbol>
makes SymbolTable
s work without issue. If it's not, the fix should be as simple as replacing typescript.UnderscoreEscapedMap
with Map
and typescript.ReadonlyUnderscoreEscapedMap
with ReadonlyMap
.
Search Terms:
Code
import * as ts from "typescript";
const p = ts.createProgram(["t.d.ts"], {});
const c = p.getTypeChecker();
p.getSourceFiles().map(f => {
f.forEachChild(n => {
if (!ts.isModuleDeclaration(n)) return;
const s = c.getSymbolAtLocation(n.name);
if (!s) return;
const scanMembers = (s: ts.Symbol) => {
if (s.valueDeclaration === undefined)
console.log("missing valueDeclaration on", s.getName());
type m = Iterator<any>
if (!s.exports) return;
if (!(Symbol.iterator in s.exports))
return console.log("not iterable", s.getName())
// error!!
for (let [/*name*/, member] of s.exports) {
scanMembers(member);
}
}
scanMembers(s);
})
})
Expected behavior:
It should be possible to iterate over a typescript.SymbolTable
.
Actual behavior:
typescript.SymbolTable
is considered not iterable.