-
Notifications
You must be signed in to change notification settings - Fork 620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add TypeScript typings to gRPC native core package #52
Add TypeScript typings to gRPC native core package #52
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the APIs that intersect, this needs to be consistent with the type definitions in packages/grpc-js-core. Can you look there and see if anything there is inconsistent with anything you wrote here?
packages/grpc-native-core/index.d.ts
Outdated
* Callback function passed to server handlers that handle methods with | ||
* unary responses. | ||
*/ | ||
type sendUnaryData = (error: ServiceError | null, value: any, trailer?: Metadata, flags?: number) => void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ��null
string appears a few times in this file, and it looks like an error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that sure looks weird... Let me get to that. And I will give the API a look in grpc-js-core
as well to make sure we are in line.
packages/grpc-native-core/index.d.ts
Outdated
*/ | ||
export interface GrpcObject { | ||
[namespace: string]: { | ||
[service: string]: typeof Client, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't exactly one namespace level; there can actually be 0 or more namespaces, and there are also message classes in there, so it should really be something like
import { Message } from "protobufjs";
export interface GrpcObject {
[name: string]: GrpcObject | typeof Client | Message,
}
I'd prefer not to mention the message classes, but without them the type definition wouldn't accurately represent the actual API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. I was a bit confused about this part when looking at the docs. I'll clear it up.
packages/grpc-native-core/index.d.ts
Outdated
* of the grpc.logVerbosity map. | ||
* @param verbosity The minimum severity to log | ||
*/ | ||
export function setLogVerbosity(verbosity: number): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logVerbosity
enum is exported below. Should the argument to this function use that enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You'r right. This could very well be the enum.
packages/grpc-native-core/index.d.ts
Outdated
* @param implementation Map of method names to method implementation | ||
* for the provided service. | ||
*/ | ||
addProtoService(service: Service, implementation: { [name: string]: handleCall }): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it's not currently documented this way, but the first argument to this function can actually be a Service
(from Protobuf.js), or a ServiceDefinition
object (defined below), or a Service object from Protobuf.js 6 (though it will be difficult to get that type definition here). This is important because the Client#service
instance variable is a valid argument to this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it.
packages/grpc-native-core/index.d.ts
Outdated
* @param creds Server credential object to be used for SSL. Pass an | ||
* insecure credentials object for an insecure port. | ||
*/ | ||
bind(port: string, creds: ServerCredentials): void; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not actually return void
; it returns a number
that is equal to the bound port, or 0 if the operation failed. The lack of documentation of this fact is an error.
packages/grpc-native-core/index.d.ts
Outdated
* @param call The call object associated with the request | ||
* @param metadata The request metadata from the client | ||
*/ | ||
constructor(call: Call, metadata: Metadata); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this isn't necessary, I would prefer to omit it. This constructor is not explicitly exposed in the API. In addition, the Call
type is defined elsewhere as the union of the client call object types, but that is not the correct type for this argument. The argument to this constructor is another type that is also not exposed in the API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove them.
packages/grpc-native-core/index.d.ts
Outdated
* @param serialize Serialization function for requests | ||
* @param deserialize Deserialization function for requests | ||
*/ | ||
constructor(call: any, metadata: Metadata, serialize: serialize, deserialize: deserialize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned above, this constructor should not be in the type definition
packages/grpc-native-core/index.d.ts
Outdated
/** | ||
* The error code, a key of `grpc.status` | ||
*/ | ||
code: number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type of code
should be the status
enum defined below.
packages/grpc-native-core/index.d.ts
Outdated
* @param googleCredential The Google credential object to use | ||
* @return The resulting credentials object | ||
*/ | ||
createFromGoogleCredential(googleCredential: GoogleCredential): CallCredentials; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe that GoogleCredential
is defined in this file, which is not surprising because gRPC does not explicitly depend on the library that that type comes from. That library is google-auth-library
. I think it would be OK to depend just on the type definitions for that library, if such a module exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a copy of the types into this file, see line 864.
The lib is written in TypeScript so it ships with it's own typings (https://github.com/google/google-auth-library-nodejs/blob/master/package.json#L10)
How would you prefer this? I dep to the lib or a copy of the type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that copy now, and I think that's the right way to handle this. But that's not the right type. I think what I called GoogleCredentials
actually corresponds to what's listed as OAuth2Client
in that library. The important part of that interface, from the point of view of how this library uses it, is the getRequestMetadata
method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's my mistake then. I'll change it to the right one.
I've put som questions into the other comments you left, but I think they've been hidden by the other changes. Would you look into them as well?
packages/grpc-native-core/index.d.ts
Outdated
* An EventEmitter. Used for unary calls. | ||
* @param call The call object associated with the request | ||
*/ | ||
constructor(call: any); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As with the server-side call classes, I think these constructors should be omitted from the type definition.
packages/grpc-native-core/index.d.ts
Outdated
*/ | ||
type handleClientStreamingCall = (call: ServerReadableStream, callback: sendUnaryData) => void; | ||
|
||
export class ServerReadableStream { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the actual API, this class inherits from a Readable stream in object mode. Could the fact that those APIs are not in the type definitions cause problems for users? This applies to all of the streaming call types on both the client and server side, as well as the UnaryClientCall
type, which inherits from EventEmitter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about this one. I think we need to explicitly inherit from those types as well otherwise something like this would cause an error.
let c: ServerUnaryCall;
c.on("data", () => {});
To make this possible we need the Node.js typings. Should I include them as a dev dependency?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm OK with depending on the Node.js typings. Wouldn't we have to include them as a regular dependency, if this index.d.ts
we're distributing in the release references it?
Also, it's not as simple as just inheriting from those types. Those types are explicitly written with the assumption that the stream is a byte stream, and it takes some intermediate type redefinitions to make them valid object stream types. You can see what I had to do for this in the other package here: https://github.com/grpc/grpc-node/blob/master/packages/grpc-js-core/src/object-stream.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't have to do as much as that, because you don't necessarily need strongly typed object streams that restrict inputs and outputs to the specific request and response types. But you at least need equivalents of the intermediate types to allow any
in the inputs to write
operations and the outputs from read
operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll look into the definitions and see what I can do with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All right, I've looked into this. The tests allow for your requested API, so I think we are good for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the changes you made here quite work. As I mentioned, the builtin stream types are written for byte streams. They handle buffers and strings, not arbitrary objects. You need to override the method definitions, like I did in that object stream TypeScript file.
Also, it looks like you didn't change all of the client stream types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When looking into the Node.js typings it seems to allow the any
type for both read
results (stream.Readable) and write
messages (stream.Writeable).
See this test file where it's possible to write an object: https://github.com/lunarway/grpc-ts-test/blob/master/index.ts#L42
Let me know if I've misunderstood something here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the readable side, you can see that the data
event restricts the values to Buffer | string
: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/index.d.ts#L5067. The Writable
type is actually fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first overload of on
allows for the any
type when reading data events.
readableStream.on("data", (chunk: object) => {});
I've made a test case in this commit: https://github.com/lunarway/grpc-ts-test/commit/23a74d585e2701a993f0b874ad017152cbc41083
packages/grpc-native-core/index.d.ts
Outdated
* @param credentials Credentials to use to connect to the server | ||
* @param {Object} options Options to apply to channel creation | ||
*/ | ||
constructor(address: string, credentials: ChannelCredentials, options?: object) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way, I creaed typings for the options here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, I'll merge them into this file. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's good to know; I would prefer not to include those in this PR. There's some complexity with handling the case where new arguments are added, and I think we'll be able to handle that better in the future after some other changes we're planning to make.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Roger. We leave them out for now then.
Thank you for your contribution. The typings file will be in grpc@1.7, which will be published soon. |
Thanks a bunch @Crevil for taking the initiative on this and getting it done! I know I've been eagerly waiting for this, so I'm sure others are too. Thanks also to @murgatroid99 for the code reviews and @connor4312 for providing his typings file to build from. |
Thank you for the great review @murgatroid99 . |
Is this available in the latest build? I am unable to find a type definition file in node_modules/grpc directory. Thanks. |
Today (hopefully) we will be publishing a prerelease package for the next version, which includes these changes. |
Following @murgatroid99's request I've moved the PR grpc/grpc#12755 to this repo instead.
From the original PR:
This is a follow up of grpc/grpc#11020. I've accidentally deleted the old gRPC fork I had as I had totally forgotten this PR.
This is a remake with all the latest API changes and the comments from the former PR added.
Further more, I've created a test repo to verify that the type comply with the documented API. It is located here for now: https://github.com/lunarway/grpc-ts-test
If it can fit into the structure of the repo, we could incorporate it to make sure the type and tests stay up to date? Let me know if there is anything I can do in that case.
From the initial PR: