Skip to content

Instantly share code, notes, and snippets.

@fuzzylimes
Created August 22, 2024 23:41
Show Gist options
  • Save fuzzylimes/c7b864ef3ca2c0e586a928a74c1aa88c to your computer and use it in GitHub Desktop.
Save fuzzylimes/c7b864ef3ca2c0e586a928a74c1aa88c to your computer and use it in GitHub Desktop.
Flatten TS Interface chain to string map
import * as ts from 'typescript';
import * as path from 'path';
function getFlattenedKeys(
typeChecker: ts.TypeChecker,
type: ts.Type,
prefix: string = ''
): string[] {
const keys: string[] = [];
const properties = type.getProperties();
for (const property of properties) {
const propertyName = property.getName();
const propertyType = typeChecker.getTypeOfSymbolAtLocation(property, property.valueDeclaration!);
if (typeChecker.isArrayType(propertyType)) {
const elementType = typeChecker.getTypeArguments(propertyType as ts.TypeReference)[0];
const nestedKeys = getFlattenedKeys(
typeChecker,
elementType,
`${prefix}${propertyName}[].`
);
keys.push(...nestedKeys);
} else if (propertyType.isClassOrInterface()) {
const nestedKeys = getFlattenedKeys(
typeChecker,
propertyType,
`${prefix}${propertyName}.`
);
keys.push(...nestedKeys);
} else {
keys.push(`${prefix}${propertyName}`);
}
}
return keys;
}
function getAllFlattenedKeys(rootDir: string, rootInterface: string): string[] {
const program = ts.createProgram([path.join(rootDir, 'dataModel.ts')], {
target: ts.ScriptTarget.ES2020,
module: ts.ModuleKind.CommonJS,
});
const typeChecker = program.getTypeChecker();
const sourceFile = program.getSourceFile(path.join(rootDir, 'dataModel.ts'));
if (!sourceFile) {
throw new Error('Source file not found');
}
const symbol = typeChecker.getSymbolAtLocation(sourceFile);
if (!symbol) {
throw new Error('Symbol not found');
}
const exportedSymbols = typeChecker.getExportsOfModule(symbol);
const rootInterfaceSymbol = exportedSymbols.find(s => s.getName() === rootInterface);
if (!rootInterfaceSymbol) {
throw new Error(`Root interface '${rootInterface}' not found`);
}
const rootType = typeChecker.getDeclaredTypeOfSymbol(rootInterfaceSymbol);
return getFlattenedKeys(typeChecker, rootType);
}
// Usage
const rootDir = './src/models/';
const flattenedKeys = getAllFlattenedKeys(rootDir, 'DataModel');
const resultMap: any = {};
flattenedKeys.forEach(key => {
resultMap[key] = null;
});
console.log(resultMap);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment