[Node]: Update http request listeners#58879
[Node]: Update http request listeners#58879vansergen wants to merge 8 commits intoDefinitelyTyped:masterfrom
Conversation
|
@vansergen Thank you for submitting this PR! This is a live comment which I will keep updated. 5 packages in this PR
Code ReviewsBecause this is a widely-used package, a DT maintainer will need to review it before it can be merged. You can test the changes of this PR in the Playground. Status
Once every item on this list is checked, I'll ask you for permission to merge and publish the changes. InactiveThis PR has been inactive for 31 days — it is considered abandoned, and therefore closed! Diagnostic Information: What the bot saw about this PR{
"type": "info",
"now": "-",
"pr_number": 58879,
"author": "vansergen",
"headCommitOid": "52c710ff8f5f2fb85d19cb793a1b52d519c5552f",
"mergeBaseOid": "3265453bdd2a7d575ea6f2d43c34f644c0e496e0",
"lastPushDate": "2022-04-04T10:37:06.000Z",
"lastActivityDate": "2022-04-04T12:03:35.000Z",
"hasMergeConflict": false,
"isFirstContribution": false,
"tooManyFiles": false,
"hugeChange": false,
"popularityLevel": "Critical",
"pkgInfo": [
{
"name": "cacheable-request",
"kind": "edit",
"files": [
{
"path": "types/cacheable-request/cacheable-request-tests.ts",
"kind": "test"
}
],
"owners": [
"BendingBender",
"paulmelnikow"
],
"addedOwners": [],
"deletedOwners": [],
"popularityLevel": "Critical"
},
{
"name": "node",
"kind": "edit",
"files": [
{
"path": "types/node/http.d.ts",
"kind": "definition"
},
{
"path": "types/node/https.d.ts",
"kind": "definition"
},
{
"path": "types/node/node-tests.ts",
"kind": "test"
},
{
"path": "types/node/test/http.ts",
"kind": "test"
},
{
"path": "types/node/test/https.ts",
"kind": "test"
},
{
"path": "types/node/v12/http.d.ts",
"kind": "definition"
},
{
"path": "types/node/v12/https.d.ts",
"kind": "definition"
},
{
"path": "types/node/v12/test/http.ts",
"kind": "test"
},
{
"path": "types/node/v12/test/https.ts",
"kind": "test"
},
{
"path": "types/node/v14/http.d.ts",
"kind": "definition"
},
{
"path": "types/node/v14/https.d.ts",
"kind": "definition"
},
{
"path": "types/node/v14/test/http.ts",
"kind": "test"
},
{
"path": "types/node/v14/test/https.ts",
"kind": "test"
},
{
"path": "types/node/v16/http.d.ts",
"kind": "definition"
},
{
"path": "types/node/v16/https.d.ts",
"kind": "definition"
},
{
"path": "types/node/v16/node-tests.ts",
"kind": "test"
},
{
"path": "types/node/v16/test/http.ts",
"kind": "test"
},
{
"path": "types/node/v16/test/https.ts",
"kind": "test"
}
],
"owners": [
"Microsoft",
"DefinitelyTyped",
"jkomyno",
"alvis",
"r3nya",
"btoueg",
"smac89",
"touffy",
"DeividasBakanas",
"eyqs",
"Hannes-Magnusson-CK",
"hoo29",
"kjin",
"ajafff",
"islishude",
"mwiktorczyk",
"mohsen1",
"n-e",
"galkin",
"parambirs",
"eps1lon",
"SimonSchick",
"ThomasdenH",
"WilcoBakker",
"wwwy3y3",
"samuela",
"kuehlein",
"bhongy",
"chyzwar",
"trivikr",
"yoursunny",
"qwelias",
"ExE-Boss",
"peterblazejewicz",
"addaleax",
"victorperin",
"ZYSzys",
"NodeJS",
"LinusU",
"wafuwafu13"
],
"addedOwners": [],
"deletedOwners": [],
"popularityLevel": "Critical"
},
{
"name": "on-finished",
"kind": "edit",
"files": [
{
"path": "types/on-finished/on-finished-tests.ts",
"kind": "test"
}
],
"owners": [
"czechboy0",
"BendingBender"
],
"addedOwners": [],
"deletedOwners": [],
"popularityLevel": "Popular"
},
{
"name": "request-stats",
"kind": "edit",
"files": [
{
"path": "types/request-stats/request-stats-tests.ts",
"kind": "test"
}
],
"owners": [
"BendingBender"
],
"addedOwners": [],
"deletedOwners": [],
"popularityLevel": "Well-liked by everyone"
},
{
"name": "stoppable",
"kind": "edit",
"files": [
{
"path": "types/stoppable/stoppable-tests.ts",
"kind": "test"
}
],
"owners": [
"EricByers",
"jplusje",
"BendingBender"
],
"addedOwners": [],
"deletedOwners": [],
"popularityLevel": "Popular"
}
],
"reviews": [
{
"type": "stale",
"reviewer": "amcasey",
"date": "2022-03-21T21:43:34.000Z",
"abbrOid": "5c11a8e"
}
],
"mainBotCommentID": 1046290458,
"ciResult": "fail",
"ciUrl": "https://github.com/DefinitelyTyped/DefinitelyTyped/commit/52c710ff8f5f2fb85d19cb793a1b52d519c5552f/checks?check_suite_id=5920276808"
} |
|
🔔 @BendingBender @paulmelnikow @microsoft @DefinitelyTyped @jkomyno @alvis @r3nya @btoueg @smac89 @Touffy @DeividasBakanas @eyqs @Hannes-Magnusson-CK @hoo29 @kjin @ajafff @islishude @mwiktorczyk @mohsen1 @n-e @galkin @parambirs @eps1lon @SimonSchick @ThomasdenH @WilcoBakker @wwwy3y3 @samuela @kuehlein @bhongy @chyzwar @trivikr @yoursunny @qwelias @ExE-Boss @peterblazejewicz @addaleax @victorperin @ZYSzys @nodejs @LinusU @wafuwafu13 @czechboy0 @EricByers @jplusje — please review this PR in the next few days. Be sure to explicitly select |
|
Did anyone have a chance to look at it? |
|
The problem of this change is generally giving a false sense of type safety, asserting types through generics is generally considered an anti-pattern as it tends to hide the actual type assertions. Then again any big library does this (including express, axios, etc. etc), I'm a little torn about doing it in node-core and would like other maintainers input in this. |
Indeed, this PR does not solve any issues but gives a tool for type safety when createServer(
{
IncomingMessage: CustomIncomingMessage,
ServerResponse: CustomServerResponse,
},
(req, res) => {
assert.ok(req instanceof CustomIncomingMessage);
assert.ok(res instanceof CustomServerResponse);
}
);Another problem is class IncomingMessage1 extends IncomingMessage {}
class IncomingMessage2 extends IncomingMessage {}
createServer({ IncomingMessage: IncomingMessage1 }, (_req, res) => {
res.req; // $ExpectType IncomingMessage1
});
createServer({ IncomingMessage: IncomingMessage2 }, (_req, res) => {
res.req; // $ExpectType IncomingMessage2
});It seems that server creation is the right place to define types that will be used in all listeners. This PR solves those problems without any breaking changes.
It could mean that such functionality would be useful because all of them are based on the |
I don't think Express does this? I think that since you can actually pass the Maybe we could type function createServer(options?: Options): Server<IncomingMessage, ServerResponse<IncomingMessage>>
function createServer<T extends IncomingMessage>(options: Options & { IncomingMessage: typeof T }): Server<T, ServerResponse<T>>
function createServer<T extends ServerResponse<IncomingMessage>>(options: Options & { ServerResponse: typeof T }): Server<IncomingMessage, T>
function createServer<T extends IncomingMessage, U extends ServerResponse<T>>(options: Options & { IncomingMessage: typeof T, ServerResponse: typeof U }): Server<T, U>That would save you having to manually type out the generic parameters when passing custom classes, and it would also ensure that you are actually passing the classes if you define the generic parameters. |
|
Re-ping @BendingBender, @paulmelnikow, @microsoft, @DefinitelyTyped, @jkomyno, @alvis, @r3nya, @btoueg, @smac89, @Touffy, @DeividasBakanas, @eyqs, @Hannes-Magnusson-CK, @hoo29, @kjin, @ajafff, @islishude, @mwiktorczyk, @mohsen1, @n-e, @galkin, @parambirs, @eps1lon, @SimonSchick, @ThomasdenH, @WilcoBakker, @wwwy3y3, @samuela, @kuehlein, @bhongy, @chyzwar, @trivikr, @yoursunny, @qwelias, @ExE-Boss, @peterblazejewicz, @addaleax, @victorperin, @ZYSzys, @nodejs, @LinusU, @wafuwafu13, @czechboy0, @EricByers, @jplusje: This PR has been out for over a week, yet I haven't seen any reviews. Could someone please give it some attention? Thanks! |
Speaking from TS's perspective, I agree. I'd consider this a pattern of last resort. @LinusU's suggestion seemed promising |
|
It has been more than two weeks and this PR still has no reviews. I'll bump it to the DT maintainer queue. Thank you for your patience, @vansergen. (Ping @BendingBender, @paulmelnikow, @microsoft, @DefinitelyTyped, @jkomyno, @alvis, @r3nya, @btoueg, @smac89, @Touffy, @DeividasBakanas, @eyqs, @Hannes-Magnusson-CK, @hoo29, @kjin, @ajafff, @islishude, @mwiktorczyk, @mohsen1, @n-e, @galkin, @parambirs, @eps1lon, @SimonSchick, @ThomasdenH, @WilcoBakker, @wwwy3y3, @samuela, @kuehlein, @bhongy, @chyzwar, @trivikr, @yoursunny, @qwelias, @ExE-Boss, @peterblazejewicz, @addaleax, @victorperin, @ZYSzys, @nodejs, @LinusU, @wafuwafu13, @czechboy0, @EricByers, @jplusje.) |
amcasey
left a comment
There was a problem hiding this comment.
My understanding from the discussion above is that there's still work to do. It would also be nice to have at least one owner sign off.
|
@vansergen One or more reviewers has requested changes. Please address their comments. I'll be back once they sign off or you've pushed new commits. Thank you! |
Indeed, we can do something like this interface ServerOptions<
Request extends typeof IncomingMessage = typeof IncomingMessage,
Response extends typeof ServerResponse= typeof ServerResponse
> {
IncomingMessage?: Request | undefined;
ServerResponse?: Response | undefined;
maxHeaderSize?: number | undefined;
insecureHTTPParser?: boolean | undefined;
}
type RequestListener<
Request extends typeof IncomingMessage = typeof IncomingMessage,
Response extends typeof ServerResponse = typeof ServerResponse
> = (req: InstanceType<Request>, res: InstanceType<Response>) => void;
function createServer<
Request extends typeof IncomingMessage = typeof IncomingMessage,
Response extends typeof ServerResponse = typeof ServerResponse,
>(requestListener?: RequestListener<Request, Response>): Server<Request, Response>;
function createServer<
Request extends typeof IncomingMessage = typeof IncomingMessage,
Response extends typeof ServerResponse = typeof ServerResponse,
>(options: ServerOptions<Request, Response>, requestListener?: RequestListener<Request, Response>): Server<Request, Response>;Does anyone agree with the suggested approach? |
|
@vansergen The CI build failed! Please review the logs for more information. Once you've pushed the fixes, the build will automatically re-run. Thanks! Note: builds which are failing do not end up on the list of PRs for the DT maintainers to review. |
|
Actually, the suggested way works modulo class MyIncomingMessage extends http.IncomingMessage {
foo: typeof foo;
}
class MyServerResponse extends http.ServerResponse<typeof MyIncomingMessage> {
bar: typeof bar;
}
let server = http.createServer(
{ ServerResponse: MyServerResponse, IncomingMessage: MyIncomingMessage },
reqListener,
);produces the following error |
|
@vansergen I haven't seen any activity on this PR in more than three weeks, and it still has problems that prevent it from being merged. The PR will be closed on May 4th (in a week) if the issues aren't addressed. |
|
@vansergen To keep things tidy, we have to close PRs that aren't mergeable and don't have activity in the last month. No worries, though — please open a new PR if you'd like to continue with this change. Thank you! |
Motivation
Checklist
npm test <package to test>.