-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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
nunjucks: fix ILoader.getSource #65883
nunjucks: fix ILoader.getSource #65883
Conversation
@not-my-profile Thank you for submitting this PR! I see this is your first time submitting to DefinitelyTyped 👋 — I'm the local bot who will help you through the process of getting things through. This is a live comment which I will keep updated. 1 package in this PRCode ReviewsBecause you edited one package and updated the tests (👏), I can help you merge this PR once someone else signs off on it. You can test the changes of this PR in the Playground. Status
All of the items on the list are green. To merge, you need to post a comment including the string "Ready to merge" to bring in your changes. Diagnostic Information: What the bot saw about this PR{
"type": "info",
"now": "-",
"pr_number": 65883,
"author": "not-my-profile",
"headCommitOid": "6853cc2663bb306735ec1ef46ca2cdfb145a64d2",
"mergeBaseOid": "d952cf91cf1bf44f412df927cf48a18670c0ca5d",
"lastPushDate": "2023-06-28T14:12:12.000Z",
"lastActivityDate": "2023-06-29T22:00:38.000Z",
"mergeOfferDate": "2023-06-29T21:08:18.000Z",
"mergeRequestDate": "2023-06-29T22:00:38.000Z",
"mergeRequestUser": "not-my-profile",
"hasMergeConflict": false,
"isFirstContribution": true,
"tooManyFiles": false,
"hugeChange": false,
"popularityLevel": "Popular",
"pkgInfo": [
{
"name": "nunjucks",
"kind": "edit",
"files": [
{
"path": "types/nunjucks/index.d.ts",
"kind": "definition"
},
{
"path": "types/nunjucks/nunjucks-tests.ts",
"kind": "test"
}
],
"owners": [
"MatthewBurstein"
],
"addedOwners": [],
"deletedOwners": [],
"popularityLevel": "Popular"
}
],
"reviews": [
{
"type": "approved",
"reviewer": "peterblazejewicz",
"date": "2023-06-29T21:07:33.000Z",
"isMaintainer": true
},
{
"type": "approved",
"reviewer": "rslabbert",
"date": "2023-06-29T00:11:40.000Z",
"isMaintainer": false
}
],
"mainBotCommentID": 1608832505,
"ciResult": "pass"
} |
🔔 @MatthewBurstein — please review this PR in the next few days. Be sure to explicitly select |
Inspecting the JavaScript source for this package found some properties that are not in the .d.ts files. nunjucks (unpkg)was missing the following properties:
|
CC @rslabbert, since you suggested the overloading. |
@not-my-profile while I think this approach makes sense, what do you think of the following? I believe it increases the typescript version requirement to ensure conditional types are available and might come with some strictness requirements, but it seems to model what is needed. I'd be happy to approve the PR as is, but I think either way it's probably a breaking change? interface ILoader<Async extends boolean | undefined> {
async: Async;
getSource: Async extends true
? (name: string, callback: Callback<Error, LoaderSource>) => void
: (name: string) => LoaderSource;
}
export interface WebLoaderOptions {
useCache?: boolean;
async?: boolean | undefined;
}
export class WebLoader<
Opts extends WebLoaderOptions,
Async extends Opts["async"] extends true ? true : false
>
extends Loader
implements ILoader<Async>
{
constructor(baseUrl?: string, opts?: Opts);
async: Async;
getSource: Async extends true
? (name: string, callback: Callback<Error, LoaderSource>) => void
: (name: string) => LoaderSource;
}
const _async = new WebLoader("", { async: true });
_async.getSource("", () => {});
const sync1 = new WebLoader("", { async: false });
sync1.getSource("");
const sync2 = new WebLoader("");
sync2.getSource(""); |
f9fb7ab
to
54a48eb
Compare
Ah yeah ... conditional types are an interesting idea but that doesn't work because the interface Foo<A extends boolean> {
foo?: A extends true ? true : false | undefined;
}
const A: Foo<true> = {}; But I think I found a nice solution by defining: type ILoader = ILoaderSync | ILoaderAsync | WebLoader; see the updated PR.
Yeah but as Ryan put it:
(and npm limits us to three numbers in the version ... so I think a patch version bump is the best we can do for this) |
That makes a lot of sense, I feel like there is an elegant solution but without doing a major restructure (difficult given the underlying code) I think this is a good place to be. This change would definitely have to be a major bump though because changing an interface to a type like this will make it no longer work in an Also I just realised I'm no longer actually marked as a reviewer on this due to a GitHub username change, so my approval is in spirit only. |
While the ILoader interface previously attempted to encompass both synchronous and asynchronous loaders, it actually failed to encompass the latter. Attempting to implement an async ILoader: class MyLoaderAsync extends nunjucks.Loader implements nunjucks.ILoader { async: true; getSource(name: string, callback) {} } previously failed with the following type error: Property 'getSource' in type 'MyLoaderAsync' is not assignable to the same property in base type 'ILoader'. Type '(name: string, callback: any) => void' is not assignable to type '{ (name: string): LoaderSource; (name: string, callback: Callback<Error, LoaderSource>): void; }'. Target signature provides too few arguments. Expected 2 or more, but got 1. (Because the ILoader interface previously declared both the signatures for a synchronous getSource and for an asynchronous getSource via overloading, which doesn't make sense ... it's either or, not both.) The previous type definitions also failed to detect mismatches between the async boolean and the getSource implementation. This commit fixes the first bug by reducing the ILoader to synchronous loaders (and introducing an ILoaderAsync interface for asynchronous loaders) and the second deficiency by introducing a stricter union.
54a48eb
to
6853cc2
Compare
Nunjucks should just use Promises but I don't think there's anything better we can do here.
Yes according to SemVer but the
Changing that comment to But as you pointed out breaking SemVer so prominently still sucks, so I changed the union type definition to: export type ILoaderAny = ILoader | ILoaderAsync | WebLoader; to avoid breaking
I am not that familiar with the PR automation here but the lifecycle diagram does say "reviews from contributors" so maybe your review could greenlight this PR even if you are no longer registered as a code owner. |
/cc @peterblazejewicz this PR has been approved by Ruben who was a type definition owner but isn't anymore because of a username change, and the only remaining owner doesn't appear to be active anymore, so it'd be great if you could review this or move it to the "Needs Maintainer Action" board, so that this doesn't unnecessarily lie idle for two weeks. |
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.
@not-my-profile thanks!
LGTM!
@rslabbert please consider adding back your handle, if you don't mind!
@not-my-profile: Everything looks good here. I am ready to merge this PR (at 6853cc2) on your behalf whenever you think it's ready. If you'd like that to happen, please post a comment saying:
and I'll merge this PR almost instantly. Thanks for helping out! ❤️ (@MatthewBurstein: you can do this too.) |
Ready to merge |
…not-my-profile While the ILoader interface previously attempted to encompass both synchronous and asynchronous loaders, it actually failed to encompass the latter. Attempting to implement an async ILoader: class MyLoaderAsync extends nunjucks.Loader implements nunjucks.ILoader { async: true; getSource(name: string, callback) {} } previously failed with the following type error: Property 'getSource' in type 'MyLoaderAsync' is not assignable to the same property in base type 'ILoader'. Type '(name: string, callback: any) => void' is not assignable to type '{ (name: string): LoaderSource; (name: string, callback: Callback<Error, LoaderSource>): void; }'. Target signature provides too few arguments. Expected 2 or more, but got 1. (Because the ILoader interface previously declared both the signatures for a synchronous getSource and for an asynchronous getSource via overloading, which doesn't make sense ... it's either or, not both.) The previous type definitions also failed to detect mismatches between the async boolean and the getSource implementation. This commit fixes the first bug by reducing the ILoader to synchronous loaders (and introducing an ILoaderAsync interface for asynchronous loaders) and the second deficiency by introducing a stricter union.
Attempting to implement an async ILoader previously failed with the following type error: