{"id":13452619,"url":"https://github.com/creditkarma/thrift-typescript","last_synced_at":"2025-04-05T05:03:04.536Z","repository":{"id":25702009,"uuid":"73042397","full_name":"creditkarma/thrift-typescript","owner":"creditkarma","description":"Generate TypeScript from Thrift IDL files","archived":false,"fork":false,"pushed_at":"2023-03-23T14:12:58.000Z","size":2928,"stargazers_count":158,"open_issues_count":33,"forks_count":32,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-24T05:49:21.534Z","etag":null,"topics":["microservices","nodejs","rpc","thrift","typescript"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/creditkarma.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-11-07T04:32:46.000Z","updated_at":"2025-01-15T19:59:17.000Z","dependencies_parsed_at":"2024-01-13T22:23:19.138Z","dependency_job_id":"07e480a8-1467-4e1e-8f08-5d6f21c84c4d","html_url":"https://github.com/creditkarma/thrift-typescript","commit_stats":{"total_commits":516,"total_committers":15,"mean_commits":34.4,"dds":0.2674418604651163,"last_synced_commit":"afd0ce0858cb54a1cedb198a4aec659b6ab90b68"},"previous_names":[],"tags_count":141,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creditkarma%2Fthrift-typescript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creditkarma%2Fthrift-typescript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creditkarma%2Fthrift-typescript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creditkarma%2Fthrift-typescript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/creditkarma","download_url":"https://codeload.github.com/creditkarma/thrift-typescript/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289409,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microservices","nodejs","rpc","thrift","typescript"],"created_at":"2024-07-31T07:01:29.385Z","updated_at":"2025-04-05T05:03:04.507Z","avatar_url":"https://github.com/creditkarma.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","📦 Legacy \u0026 Inactive Projects"],"sub_categories":[],"readme":"# Thrift TypeScript\n\nGenerate TypeScript from Thrift IDL files.\n\n## Installation\n\n```sh\n$ npm install --save @creditkarma/thrift-typescript\n```\n\n## Usage\n\nThrift TypeScript provides both a JavaScript and a command line API.\n\nGiven the following files\n\nthrift/simple.thrift\n\n```c\nstruct MyStruct {\n    1: required i32 id,\n    2: required bool field1,\n    # 3: required string field,\n    4: required i16 field,\n}\n```\n\nYou can generate TypeScript via the command line:\n\n```sh\n$ thrift-typescript --target apache --rootDir . --sourceDir thrift --outDir codegen simple.thrift\n```\n\nThe available options are:\n\n* --rootDir: This is used to resolve out and source directories. Defaults to current directory.\n* --outDir: The directory to save generated files to. Will be created if it doesn't exist. Defaults to 'codegen'.\n* --sourceDir: The directory to search for source Thrift files. Defaults to 'thrift'.\n* --target: The core library to generate for, either 'apache' or 'thrift-server'. Defaults to 'apache'.\n* --strictUnions: Should we generate strict unions (Only available for target = 'thrift-server'. More on this below). Defaults to undefined.\n* --fallbackNamespace: The namespace to fallback to if no 'js' namespace exists. Defaults to 'java'. Set to 'none' to use no namespace.\n* --withNameField: Should we generate a `__name` field on each struct-like object that contains its Thrift name (Only available for target = 'thrift-server'). Defaults to undefined.\n\nAll other fields are assumed to be source files.\n\nIf no explicit list of files is provided all files ending in '.thrift' found in the sourceDir will be used.\n\nYou can gen code from more than one Thrift file:\n\n```sh\n$ thrift-typescript one.thrift two.thrift three.thrift\n```\n\n#### JavaScript API\n\nYou can also generate files using the JavaScript API:\n\n```typescript\nimport { generate } from '@creditkarma/thrift-typescript'\n\n// Generates TypeScript and saves to given outDir\ngenerate({\n    rootDir: '.',\n    sourceDir: 'thirft',\n    outDir: 'codegen',\n    target: 'thrift-server',\n    files: [\n        'simple.thrift'\n    ],\n    fallbackNamespace: 'java',\n})\n```\n\n#### Thrift to String\n\nYou can also generate TypeScript from a string of Thrift without saving to file.\n\nNote: This method of code generation does not support includes. The Thrift generator must be able to resolve all identifiers which it can't do without a description of the file structure.\n\n```typescript\nimport { readFileSync } from 'fs'\nimport { make } from '@creditkarma/thrift-typescript'\n\nconst rawThrift: string = readFileSync('./thrift/simple.thrift', 'utf-8')\nconst generatedCode: string = make(rawThrift)\n```\n\n## Thrift Server\n\n*v2.x of Thrift TypeScript equires @creditkarma/thrift-server v0.7.0 or higher*\n\nWhile Thrift TypeScript can be used to generate code comaptible with the [Apache Thrift Library](https://github.com/apache/thrift/tree/master/lib/nodejs), it is recommended to use with [Thrift Server](https://github.com/creditkarma/thrift-server). Details on the Apache usage are below.\n\nThrift Server adds Thrift support to Express or Hapi with plugins or middleware. The other advantange of using the codegen with Thrift Server is the addition of context to service clients and service handlers. Context can be used to do things like auth or tracing in Thrift service methods. Context is an optional final parameter to all service handler methods and all service client methods.\n\nInstall the Thrift Server implementation for your server of choice. For this example we will be using express middleware and the request http client library.\n\n```sh\n$ npm install --save @creditkarma/thrift-server-core\n$ npm install --save @creditkarma/thrift-server-express\n$ npm install --save @creditkarma/thrift-client\n$ npm install --save express\n$ npm install --save request\n$ npm install --save @types/express\n$ npm install --save @types/request\n```\n\nGiven this service let's build a client and server based on our generated code.\n\n```c\nservice Caluculator {\n    i32 add(1: i32 left, 2: i32 right)\n    i32 subtract(1: i32 left, 2: i32 right)\n}\n```\n\nRun codegen for your Thrift service. The `target` option is required here, otherwise the generated code will only work with the Apache libs.\n\n```sh\n$ thrift-typescript --target thrift-server --rootDir . --sourceDir thrift --outDir codegen\n```\n\n### Client\n\nIn this example we are using the Request library as our underlying connection instance. The options for Request (CoreOptions) are our request context.\n\nYou'll notice that the Client class is a generic. The type parameter represents the type of the context. This is usually going to be of type `CoreOptions` from the Request library.\n\n```typescript\nimport {\n    createHttpClient,\n    HttpConnection,\n} from '@creditkarma/thrift-client'\n\nimport * as request from 'request'\nimport { CoreOptions } from 'request'\n\nimport { Calculator } from './codegen/calculator'\n\nconst CONFIG = {\n    hostName: 'localhost',\n    port: 8045\n}\n\nconst thriftClient: Calculator.Client\u003cCoreOptions\u003e = createHttpClient(Calculator.Client, CONFIG)\n\nthriftClient.add(5, 7, { headers: { 'X-Trace-Id': 'xxxxxx' } })\n    .then((response: number) =\u003e {\n        expect(response).to.equal(12)\n        done()\n    })\n```\n\n### Server\n\nIn the server we can then inspect the headers we set in the client.\n\n```typescript\nimport * as bodyParser from 'body-parser'\nimport * as express from 'express'\nimport { ThriftServerExpress } from '@creditkarma/thrift-server-express'\n\nimport {\n    Calculator,\n} from './codegen/calculator'\n\n// express.Request is the context for each of the service handlers\nconst serviceHandlers: Calculator.IHandler\u003cexpress.Request\u003e = {\n    add(left: number, right: number, context?: express.Request): number {\n        if (context \u0026\u0026 context.headers['x-trace-id']) {\n            // You can trace this request, perform auth, or use additional middleware to handle that.\n        }\n        return left + right\n    },\n    subtract(left: number, right: number, context?: express.Request): number {\n        return left - right;\n    },\n}\n\nconst PORT = 8090\n\nconst app = express()\n\napp.use(\n    '/thrift',\n    bodyParser.raw(),\n    ThriftServerExpress(Calculator.Processor, serviceHandlers),\n)\n\napp.listen(PORT, () =\u003e {\n    console.log(`Express server listening on port: ${PORT}`)\n})\n\n```\n\n### Generated Data Types\n\nWhen generating TypeScript from Thrift source what data types are generated?\n\n#### Simple Types\n\nThese are: booleans, strings, numbers, sets, maps, lists, enums and typedefs. All of these translate almost directly to TypeScript.\n\nGiven Thrift:\n\n```c\nconst bool FALSE_CONST = false\nconst i32 INT_32 = 32\nconst i64 INT_64 = 64\nconst list\u003cstring\u003e LIST_CONST = ['hello', 'world', 'foo', 'bar']\nconst set\u003cstring\u003e SET_CONST = ['hello', 'world', 'foo', 'bar']\nconst map\u003cstring,string\u003e MAP_CONST = { 'hello': 'world', 'foo': 'bar' }\n\nenum Colors {\n    RED,\n    GREEN,\n    BLUE,\n}\n\ntypedef string name\n```\n\nGenerated TypeScript:\n\n```typescript\nexport const FALSE_CONST: boolean = false;\nexport const INT_32: number = 32;\nexport const INT_64: thrift.Int64 = new thrift.Int64(64);\nexport const LIST_CONST: Array\u003cstring\u003e = [\"hello\", \"world\", \"foo\", \"bar\"];\nexport const SET_CONST: Set\u003cstring\u003e = new Set([\"hello\", \"world\", \"foo\", \"bar\"]);\nexport const MAP_CONST: Map\u003cstring, string\u003e = new Map([[\"hello\", \"world\"], [\"foo\", \"bar\"]]);\n\nexport enum Colors {\n    RED,\n    GREEN,\n    BLUE\n}\n\nexport type name = string;\n```\n\nThe only interesting thing here is the handling of `i64`. JavaScript doesn't support a full 64-bits of integer percision, so we wrap the value in an `Int64` object. You will notice that this doesn't really help in cases where you define a constant or default value in your Thrift file, but it does allow 64-bit integers received from outside of JS to be handled correctly. The object is exported from `@creditkarma/thrift-server-core` and extends [node-int64](https://github.com/broofa/node-int64).\n\n#### Struct\n\nA struct is intuitively analogous to an interface.\n\nGiven Thrift:\n\n```c\nstruct User {\n    1: required string name\n    2: string email\n    3: required i32 id\n}\n```\n\nGenerated TypeScript:\n\n```typescript\nexport interface IUser {\n    name: string\n    email?: string\n    id: number\n}\n```\n\n*Note: We adopt the convention of prefixing interfaces names with a capital 'I'.*\n\nOnly fields that are explicitly required loose the `?`.\n\n##### The `__name` Field\n\nYou can pass an option to generate an additional property on each struct-like (structs, unions, exceptions) object that is its literal name in the Thrift file.\n\nFor example if we rendered the `User` struct with the `--withNameField` option the generated TypeScript would change:\n\n```typescript\nexport interface IUser {\n    __name: \"User\"\n    name: string\n    email?: string\n    id: number\n}\n```\n\nWhen generating with this option any data types you create and pass into a client method do not need the `__name` field. However, any data you get back from a service will contain this additional property.\n\n#### Union\n\nUnions in Thrift are very similar to structs. The difference is they only allow one field to be set. They also require that one field is set. Implicitly all fields are optional, but one field must be set.\n\nSo, this translates into a struct with all optional fields:\n\nGiven Thrift:\n\n```c\nunion MyUnion {\n    1: string option1\n    2: i32 option2\n}\n```\n\nGenerated TypeScript (without strict unions):\n\n```typescript\nexport interface IMyUnion = {\n    option1?: string\n    option2?: undefined\n}\n```\n\n*Note: The difference here is that a runtime error will be raised if one of the fields isn't set or if more than one of the fields is set.*\n\n#### Exception\n\nExceptions are errors that can be thrown by service methods. It is more natural in JS/TS to create and throw new errors. So our defined exceptions will become JS classes.\n\nGiven Thrift:\n\n```c\nexception MyException {\n    1: string message\n    2: i32 code\n}\n```\n\nGenerated TypeScript:\n\n```typescript\nexport class MyException extends thrift.StructLike implements IMyException {\n    public message: string\n    public code?: number\n    constructor(args?: { message?: string, code?: number }) {\n        // ...\n    }\n}\n```\n\nThen in your service client you could just throw the exception as you would any JS error `throw new MyException({ message: 'whoops', code: 500 });`\n\n#### Service\n\nServices are a little more complex. There are two parts to a service. There is the `Client` for sending service requests and the `Processor` for handling service requests. The service `Client` and the service `Processor` are each generated classes. They are wrapped, along with some other internal objects, in a `namespace` that has the name of your service.\n\nGiven Thrift:\n\n```c\nservice MyService {\n    User getUser(1: i32 id) throws (1: MyException exp);\n}\n```\n\nGenerated TypeScript:\n\n```typescript\nexport namespace MyService {\n    export class Client\u003cContext\u003e {\n        constructor(connection: thrift.IThriftConnection\u003cContext\u003e) {\n            // ...\n        }\n        getUser(id: number): Promise\u003cUser\u003e {\n            // ...\n        }\n    }\n    export interface IHandler\u003cContext\u003e {\n        getUser(id: number, context?: Context): User | Promise\u003cUser\u003e\n    }\n    export class Processor {\n        constructor(handler: IHandler\u003cContext\u003e) {\n            // ...\n        }\n        public process(input: thrift.TProtocol, output: thrift.TProtocol, context: Context): Promise\u003cBuffer\u003e {\n            // ...\n        }\n    }\n}\n```\n\nThe `Client` is pretty straight forward. You create a `Client` instance and you can call service methods on it. The inner-workings of the `Processor` aren't something consumers need to concern themselves with. The more interesting bit is `IHandler`. This is the interface that service teams need to implement in order to meet the promises of their service contract. Create an object that satisfies `\u003cservice-name\u003e.IHandler` and pass it to the construction of `\u003cservice-name\u003e.Processor` and everything else is handled for you.\n\n#### Loose Types\n\nGiven these two structs:\n\n```c\nstruct User {\n    1: required i64 id\n}\n\nstruct Profile {\n    1: required User user\n    2: binary data\n    3: i64 lastModified\n}\n```\n\nThere is something of a difference between how we want to handle things in TypeScript and how data is going to be sent over the wire. Because of this when we generate interfaces for these structs we generate two interfaces for each struct, one is an exact representation of the Thrift, the other is something looser that provides more flexibility to working with the data in JavaScript.\n\nThe main difference is that fields marked as `i64` can be represented as a `number`, as `string` or an `Int64` object and `binary` can be represented as either a `string` or a `Buffer` object.\n\nJavaScript traditionally (`bigint` is new and not fully supported yet) does not support 64-bit integers. This means we need to wrap the Thrift `i64` type in the `Int64` object to maintain precision. In your TypeScript code you may be working with these just as `number` (confident JavaScript's 53-bit precision is good enough for you) or as a `string`. These loose types allow you to do that and the generated code will handle the conversions to `Int64` for you.\n\nGenerated TypeScript:\n\n```typescript\ninterface IUser {\n    id: thrift.Int64\n}\ninterface IUserArgs {\n    id: number | string | thrift.Int64\n}\ninterface IProfile {\n    user: IUser\n    data?: Buffer\n    lastModified?: thrift.Int64\n}\ninterface IProfileArgs {\n    user: IUserArgs\n    data?: string | Buffer\n    lastModified?: number | string | thrift.Int64\n}\n```\n\nThe names of loose interfaces just append `Args` onto the end of the interface name. The reason for this is these interfaces will most often be used as arguments in your code.\n\nWhere are the loose interfaces used? The loose interfaces can be used anywhere you, the application developer, are giving data to the generated code, either as the arguments to a client method or the return value of a service handler.\n\nIf we had this service:\n\n```c\nservice ProfileService {\n    Profile getProfileForUser(1: User user)\n    User getUser(1: i64 id)\n}\n```\n\nAnd generated TypeScript:\n\n```typescript\nnamespace ProfileService {\n    export class Client\u003cContext\u003e {\n        constructor(connection: thrift.IThriftConnection\u003cContext\u003e) {\n            // ...\n        }\n        getProfileForUser(user: IUserArgs, context?: Context): Promise\u003cIProfile\u003e {\n            // ...\n        }\n        getUser(id: number | string | Int64): Promise\u003cIUser\u003e {\n            // ...\n        }\n    }\n    export interface IHandler\u003cContext\u003e {\n        getProfileForUser(user: IUser, context: Context): Promise\u003cIProfileArgs\u003e\n        getUser(id: Int64, context: Context): Promise\u003cIUserArgs\u003e\n    }\n}\n```\n\nAs you can see from this sketch of generated types when data leave application code and crossed the boundary into the generated code you can pass loose values, when the data comes from generated code it will always be of the strict types.\n\nWe can use a `User` object where the `id` is a `number` or a `string` without having to wrap it in `Int64`. These conversions are handled for us. A `number` passed in is wrapped in `Int64` by using the `Int64` constructor: `new Int64(64)`. A `string` passed in place of an `Int64` is converted using the static `fromDecimalString` method: `Int64.fromDecimalString('64')`. Similarly `string` data can be passed to a `binary` field and the conversion to `Buffer` is handled under the hood. This are just convinience interfaces to make handling the Thrift objects in TypeScript a little easier. You will notice service methods always return an object of the more strict interface. Also, the more strict interface can always be passed where the loose interface is expected.\n\n#### Sending Data Over the Wire\n\nWhen it comes to struct-like data types (struct, union and exception) usually you don't need to know much more than what data types are generated. However, in addition to the generated interface/union/class the code generator also creates a companion object that knows how to send the given object over the wire.\n\nLooking back at the `User` object from our struct example, in addition to the interface, the code generator creates a codec object like this:\n\n```typescript\nexport const UserCodec: thrift.IStructCodec\u003cIUserArgs, IUser\u003e {\n    encode(obj: IUserArgs, output: thrift.TProtocol): void {\n        // ...\n    },\n    decode(input: thrift.TProtocol): IUser {\n        // ...\n    }\n}\n```\n\nIt's just an object that knows how to read the given object from a Thrift Protocol or write the given object to a Thrift Protocol.\n\nThe codec will always follow this naming convention, just appending `Codec` onto the end of your struct name.\n\n### Strict Unions\n\n*Note: Strict unions require `thrift-server` version `0.13.x` or higher.*\n\nThis is an option only available when generating for `thrift-server`. This option will generate Thrift unions as TypeScript unions. This changes the codegen in a few significant ways.\n\nBack with our example union definition:\n\n```c\nunion MyUnion {\n    1: string option1\n    2: i32 option2\n}\n```\n\nWhen compiling with the `--strictUnions` flag we now generate TypeScript like this:\n\n```typescript\nenum MyUnionType {\n    MyUnionWithOption1 = \"option1\",\n    MyUnionWithOption2 = \"option2\"\n}\ntype MyUnion = IMyUnionWithOption1 | IMyUnionWithOption2\ninterface IMyUnionWithOption1 {\n    __type: MyUnionType.MyUnionWithOption1\n    option1: string\n    option2?: undefined\n}\ninterface IMyUnionWithOption2 {\n    __type: MyUnionType.MyUnionWithOption2\n    option1?: undefined\n    option2: number\n}\ntype MyUnionArgs = IMyUnionWithOption1Args | IMyUnionWithOption2Args\ninterface IMyUnionWithOption1Args {\n    option1: string\n    option2?: undefined\n}\ninterface IMyUnionWithOption2Args {\n    option1?: undefined\n    option2: number\n}\n```\n\nThe `enum` represents all potential values of the `__type` property attached to each variation of our union. Instead of generating one `interface` with optional properties we generate one interface for each field where that field is required. Our resulting `type` is then the union of multiple interfaces each with only one property. This provides compile-time guarantees that we are setting one and only one field for the union.\n\nThe loose interfaces, the `Args` interfaces, behave much like the loose interfaces for structs. They allow you to use `number` in place of `Int64` or allow you to pass either `string` or `Buffer` for `binary` types. In addition, they also forgo the `__type` property. In the codegen we can tell what you are passing by the fields you set. This means in most instances you don't need to provide the `__type` property. You can use the loose interfaces as the return value for service functions or as the arguments for client methods.\n\nThis output is more complex, but it allows us to do a number of things. The most significant of which may be that it allows us to take advantage of discriminated unions in our application code:\n\n```typescript\nfunction processUnion(union: MyUnion) {\n    switch (union.__type) {\n        case MyUnionType.MyUnionWithOption1:\n            // Do something\n        case MyUnionType.MyUnionWithOption2:\n            // Do something\n        default:\n            const _exhaustiveCheck: never = union\n            throw new Error(`Non-exhaustive match for type: ${_exhaustiveCheck}`)\n    }\n}\n```\n\nThe fact that each interface we generate defines one required field and some n number of optional `undefined` fields we can do things like check `union.option2 !== undefined` without a compiler error, but we will get a compiler error if you try to use a value that shouldn't exist on a given union. This expands the ways you can operate on unions to be more general.\n\nUsing this form will require that you prove to the compiler that one (and only one) field is set for your unions.\n\nIn addition to the changed types output, the `--strictUnions` flag changes the output of the `Codec` object. The `Codec` object will have one additional method `create`. The `create` method takes one of the loose interfaces and coerces it into the strict interface (including the `__type` property).\n\nFor the example `MyUnion` that would be defined as:\n\n```typescript\nconst MyUnionCodec: thrift.IStructToolkit\u003cIUserArgs, IUser\u003e { = {\n    create(args: MyUnionArgs): MyUnion {\n        // ...\n    },\n    encode(obj: IUserArgs, output: thrift.TProtocol): void {\n        // ...\n    },\n    decode(input: thrift.TProtocol): IUser {\n        // ...\n    }\n}\n```\n\n*Note: In a future breaking release all the `Codec` objects will be renamed to `Toolkit` as they will provide more utilities for working with defined Thrift objects.*\n\n\n## Apache Thrift\n\nThe generated code can also work with the [Apache Thrift Library](https://github.com/apache/thrift/tree/master/lib/nodejs).\n\n```sh\n$ npm install --save thrift\n$ npm install --save @types/thrift\n```\n\nGiven this service let's build a client and server based on our generated code.\n\n```c\nservice Calculator {\n    i32 add(1: i32 left, 2: i32 right)\n    i32 subtract(1: i32 left, 2: i32 right)\n}\n```\n\nRun codegen for your Thrift service. Here the `--target` option isn't needed as `apache` is the default build target.\n\n```sh\n$ thrift-typescript --rootDir . --sourceDir thrift --outDir codegen\n```\n\n### Client\n\n```typescript\nimport {\n    createHttpConnection,\n    createHttpClient,\n    HttpConnection,\n} from 'thrift'\n\nimport { Calculator } from './codegen/calculator'\n\n// The location of the server endpoint\nconst CONFIG = {\n    hostName: 'localhost',\n    port: 8045\n}\n\nconst options = {\n    transport: TBufferedTransport,\n    protocol: TBinaryProtocol,\n    https: false,\n    headers: {\n        Host: config.hostName,\n    }\n}\n\nconst connection: HttpConnection = createHttpConnection(CONFIG.hostName, CONFIG.port, options)\nconst thriftClient: Calculator.Client = createHttpClient(Calculator.Client, connection)\n\n// All client methods return a Promise of the expected result.\nthriftClient.add(5, 6).then((result: number) =\u003e{\n    console.log(`result: ${result}`)\n})\n```\n\n### Server\n\n```typescript\nimport {\n    createWebServer,\n    TBinaryProtocol,\n    TBufferedTransport,\n} from 'thrift'\n\nimport { Calculator } from './codegen/calculator'\n\n// Handler: Implement the Calculator service\nconst myServiceHandler = {\n    add(left: number, right: number): number {\n        return left + right\n    },\n    subtract(left: number, right: number): number {\n        return left - right\n    },\n}\n\n// ServiceOptions: The I/O stack for the service\nconst myServiceOpts = {\n    handler: myServiceHandler,\n    processor: Calculator,\n    protocol: TBinaryProtocol,\n    transport: TBufferedTransport\n}\n\n// ServerOptions: Define server features\nconst serverOpt = {\n    services: {\n        '/': myServiceOpts\n    }\n}\n\n// Create and start the web server\nconst port: number = 8045;\ncreateWebServer(serverOpt).listen(port, () =\u003e {\n    console.log(`Thrift server listening on port ${port}`)\n})\n```\n\n## Notes\n\nThe gererated code can be used with many of the more strict tsc compiler options.\n\n```json\n{\n    \"compilerOptions\": {\n        \"noImplicitAny\": true,\n        \"noImplicitThis\": true,\n        \"strictNullChecks\": true,\n        \"strictFunctionTypes\": true,\n        \"noUnusedLocals\": true\n    }\n}\n```\n\n## Development\n\nInstall dependencies with\n\n```sh\nnpm install\n```\n\n### Build\n\n```sh\nnpm run build\n```\n\n### Run test in watch mode\n\n```sh\nnpm run test:watch\n```\n\n## Contributing\n\nFor more information about contributing new features and bug fixes, see our [Contribution Guidelines](https://github.com/creditkarma/CONTRIBUTING.md).\nExternal contributors must sign Contributor License Agreement (CLA)\n\n## License\n\nThis project is licensed under [Apache License Version 2.0](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreditkarma%2Fthrift-typescript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcreditkarma%2Fthrift-typescript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreditkarma%2Fthrift-typescript/lists"}