Skip to content

Instantly share code, notes, and snippets.

@wojpawlik
Last active October 28, 2020 13:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wojpawlik/885dbe80be82e706e9e84c967269e17b to your computer and use it in GitHub Desktop.
Save wojpawlik/885dbe80be82e706e9e84c967269e17b to your computer and use it in GitHub Desktop.
Lists methods without TypeScript typings.
# http://editorconfig.org/
root = true
[*]
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
indent_size = 3
node_modules/

Lists methods without TypeScript typings.

Usage:

mistypes <js> --- <dts>
#!/usr/bin/env ts-node-script -T
import * as ts from "typescript";
import { tsIds } from "./ts-ids";
const files = process.argv.slice(2);
interface InOut {
minuend: string[];
subtrahend: string[];
}
function inOut(files: readonly string[]): InOut {
let idx = files.findIndex((s) => s === "---");
if (idx === -1) {
idx = Infinity;
}
return { minuend: files.slice(0, idx), subtrahend: files.slice(idx + 1) };
}
function* difference(minuend: Iterable<string>, subtrahend: Iterable<string>) {
const set = new Set(subtrahend);
for (const item of minuend) {
if (!set.has(item)) {
yield item;
}
}
}
function filesIds(files: readonly string[]) {
const program = ts.createProgram(files, { allowJs: true });
return program.getSourceFiles().flatMap(tsIds);
}
const { minuend, subtrahend } = inOut(files);
// It breaks without Array.from
for (const entry of Array.from(
difference(filesIds(minuend), filesIds(subtrahend))
)) {
console.log(entry);
}
{
"name": "mistypes",
"version": "0.0.0",
"description": "Lists methods without TypeScript typings",
"bin": "mistypes.ts",
"dependencies": {
"ts-node": "^8.8.2",
"typescript": "^3.8.3"
},
"devDependencies": {
"@types/node": "^13.11.1",
"prettier": "2.0.4"
},
"repository": {
"type": "git",
"url": "https://gist.github.com/885dbe80be82e706e9e84c967269e17b.git"
},
"keywords": [
"typescript"
],
"author": "Wojciech Pawlik <woj.pawlik@gmail.com>",
"license": "ISC"
}
import * as ts from "typescript";
const isStatic = ({ kind }: ts.Modifier) => kind === 120;
export function tsIds(file: ts.SourceFile): string[] {
const ids: string[] = [];
ts.forEachChild(file, (node) => {
if (ts.isClassDeclaration(node)) {
node.forEachChild((member) => {
if (ts.isMethodDeclaration(member)) {
const sep = member.modifiers?.some(isStatic) ? "." : "::";
ids.push(
node.name?.escapedText + sep + member.name.getText(file) + "()"
);
}
});
}
});
return ids;
}
{
"compilerOptions": {
"module": "CommonJS",
"noEmit": true,
"strict": true,
"target": "ES2019"
}
}
@Ethan-Arrowood
Copy link

Wait this looks awesome. How extensively have you tested it?

@wojpawlik
Copy link
Author

Thanks @Ethan-Arrowood.

I wrote this just for telegraf/telegraf#979 and only tested it there. I stopped working on it as soon as it was usable from npx and I didn't notice any false negatives. I'm not experienced enough with TypeScript API to sustainably continue improving it.

@Ethan-Arrowood
Copy link

Nice! I'll give this a shot with Fastify soon.

@wojpawlik
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment