-
Notifications
You must be signed in to change notification settings - Fork 74
Refactor: Enabled typescript strict mode #504
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,16 +3,18 @@ import api, { handleResponseType } from '../../src/utils/api'; | |
| describe('api', () => { | ||
| describe('handleResponseType', () => { | ||
| test('should handle missing Content-Type', async () => { | ||
| const responseText = `responseText`; | ||
| const ok = false; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you could move this line to the object below 😉
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes but I kept them separate because
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| const response: Response = { | ||
| url: 'http://localhost:8080/-/packages', | ||
| ok: false, | ||
| ok: ok, | ||
tmkn marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| headers: new Headers(), | ||
| text: async () => responseText, | ||
| } as Response; | ||
|
|
||
| const handled = await handleResponseType(response); | ||
|
|
||
| // Should this actually return [false, null] ? | ||
| expect(handled).toBeUndefined(); | ||
| expect(handled).toEqual([ok, responseText]); | ||
| }); | ||
|
|
||
| test('should test tgz scenario', async () => { | ||
|
|
@@ -94,9 +96,9 @@ describe('api', () => { | |
|
|
||
| expect(fetchSpy).toHaveBeenCalledWith('https://verdaccio.tld/resource', { | ||
| credentials: 'same-origin', | ||
| headers: { | ||
| headers: new Headers({ | ||
| Authorization: 'Bearer token-xx-xx-xx', | ||
| }, | ||
| }), | ||
| method: 'GET', | ||
| }); | ||
| expect(response).toEqual({ c: 3 }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,7 +6,7 @@ import '../../types'; | |||||||||
| * @param {object} response | ||||||||||
| * @returns {promise} | ||||||||||
| */ | ||||||||||
| export function handleResponseType(response: Response): Promise<[boolean, Blob | string] | void> { | ||||||||||
| export function handleResponseType(response: Response): Promise<[boolean, any]> { | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just wondering why do we remove types here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it also returns json: Line 16 in f845712
So in this case it returns the tuple [boolean, any] since .json() returns any.
So to be technically correct the return type should be Now you could write it like Line 59 in f845712
errors, since the signature for the request method looks like this:Line 33 in f845712
You would then need a typecast at resolve(response[1] as any); which I tried to avoid or go down a rabbit hole of type errors/potential rewrite of the ajax logic.
As I said the ajax functionality is a little bit cumbersome to type as it is. The main cause being that the return type is determined dynamically at runtime (in the Line 66 in f845712
The server could return a string, in which case there is no code to handle the case that it actually returned a string but json was expected.
So in short, without introducing too many type casts/changes to the existing logic, I changed it to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @tmkn :) well explained. |
||||||||||
| if (response.headers) { | ||||||||||
| const contentType = response.headers.get('Content-Type'); | ||||||||||
| if (contentType && contentType.includes('application/pdf')) { | ||||||||||
|
|
@@ -26,7 +26,7 @@ export function handleResponseType(response: Response): Promise<[boolean, Blob | | |||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| return Promise.resolve(); | ||||||||||
| return Promise.all([response.ok, response.text()]); | ||||||||||
juanpicado marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
| } | ||||||||||
|
|
||||||||||
| class API { | ||||||||||
|
|
@@ -36,10 +36,11 @@ class API { | |||||||||
| } | ||||||||||
|
|
||||||||||
| const token = storage.getItem('token'); | ||||||||||
| if (token && options.headers && typeof options.headers['Authorization'] === 'undefined') { | ||||||||||
| options.headers = Object.assign({}, options.headers, { | ||||||||||
| ['Authorization']: `Bearer ${token}`, | ||||||||||
| }); | ||||||||||
| const headers = new Headers(options.headers); | ||||||||||
|
|
||||||||||
| if (token && headers.has('Authorization') === false) { | ||||||||||
| headers.set('Authorization', `Bearer ${token}`); | ||||||||||
| options.headers = headers; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (!['http://', 'https://', '//'].some(prefix => url.startsWith(prefix))) { | ||||||||||
|
|
||||||||||
This file was deleted.
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.
sometimes when TypeScript can’t infer the type, it makes sense to pass a generic parameter, but in most of the cases TS can cleverly infer the type for useState, especially when we pass a default value... So I believe that passing a generic parameter here is not really necessary + it's very verbose
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.
While I agree, in some
useStatecalls they were necessary. So in order to not have diverging coding styles I unified theuseStatedeclarations in places that were affected. Also while they not seem helpful right now, because the code works, TypeScript is now able to error when you try to initialize a state with the wrong type thanks to the generic usage, after all this PR is all about increasing the type safety 😃Uh oh!
There was an error while loading. Please reload this page.
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.
While Typescript infers values, it does based on how is initialized. So without type anyone could change to
123and will be hard to notice the original author actually wants only boolean.while the type, perfectly is noticeable and any contributor is aware can only use booleans and not any other value.
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.
Anyway, I could not find a eslint rule for this, so, let's use common sense. Let's use types for complex objects while for native let's Typescript do the magic.
Uh oh!
There was an error while loading. Please reload this page.
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.
And I refer to
useState. For instance things likePromise<string>orconst [packageMeta, setPackageMeta] = useState<PackageMetaInterface>();make totally sense.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.
to add there is a subtle difference in the inferred typings for
useStateused like this:
useState<boolean>();the type will beboolean | undefinedwhileuseState<boolean>(true);the type will be justbooleanI just like to be more explicit. e.g.
if
getValuereturns astring, thenuseStatewill not error even though we expect aboolean, it will happily infer thestringtype and will instead error further down below, while ifuseStatewould have made use of the generic to specify the type, it would have error'd.