Skip to content

Instantly share code, notes, and snippets.

@dyerw
Created June 18, 2020 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dyerw/bec118a2a336cea46f620ed83af124a4 to your computer and use it in GitHub Desktop.
Save dyerw/bec118a2a336cea46f620ed83af124a4 to your computer and use it in GitHub Desktop.
Play with generating TS Interfaces from Avro Schemas
import * as ts from "typescript";
// Haven't dealt with arrays and records
type AvscType = "string" | "int" | "null";
type TsTypes =
| ts.SyntaxKind.StringKeyword
| ts.SyntaxKind.NumberKeyword
| ts.SyntaxKind.NullKeyword;
interface AvscField {
name: string;
type: AvscType | AvscType[];
}
interface AvscRecord {
namespace: string;
name: string;
fields: AvscField[];
}
const avscToTsTypeLookup: Record<AvscType, TsTypes> = {
["string"]: ts.SyntaxKind.StringKeyword,
["int"]: ts.SyntaxKind.NumberKeyword,
["null"]: ts.SyntaxKind.NullKeyword,
};
function convertAvscFieldToTsPropertySignature(
avscField: AvscField
): ts.PropertySignature {
const propertyName = ts.createIdentifier(avscField.name);
if (typeof avscField.type === "string") {
const type = ts.createKeywordTypeNode(avscToTsTypeLookup[avscField.type]);
return ts.createPropertySignature(
undefined,
propertyName,
undefined,
type,
undefined
);
}
if (avscField.type instanceof Array) {
const types = avscField.type.map((t) =>
ts.createKeywordTypeNode(avscToTsTypeLookup[t])
);
const type = ts.createUnionTypeNode(types);
return ts.createPropertySignature(
undefined,
propertyName,
undefined,
type,
undefined
);
}
throw new Error("Pretty sure it's impossible for this to be reached");
}
function convertAvscRecordToTsInterface(avscRecord: AvscRecord) {
const interfaceName = ts.createIdentifier(avscRecord.name);
const properties = avscRecord.fields.map(
convertAvscFieldToTsPropertySignature
);
return ts.createInterfaceDeclaration(
undefined,
undefined,
interfaceName,
undefined,
undefined,
properties
);
}
const resultFile = ts.createSourceFile(
"someFileName.ts",
"",
ts.ScriptTarget.Latest,
false,
ts.ScriptKind.TS
);
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
const test: AvscRecord = {
name: "Foo",
namespace: "foo.foo",
fields: [
{ name: "bar", type: ["string", "null"] },
{ name: "baz", type: "string" },
{ name: "bop", type: "int" },
],
};
const result = printer.printNode(
ts.EmitHint.Unspecified,
convertAvscRecordToTsInterface(test),
resultFile
);
console.log(result);
//Output:
interface Foo {
bar: string | null;
baz: string;
bop: number;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment