Skip to content
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

Revert #3002 - set type of data to any #4141

Closed
ImRodry opened this issue Oct 5, 2021 · 48 comments · Fixed by #4186
Closed

Revert #3002 - set type of data to any #4141

ImRodry opened this issue Oct 5, 2021 · 48 comments · Fixed by #4186

Comments

@ImRodry
Copy link
Contributor

ImRodry commented Oct 5, 2021

Is your feature request related to a problem? Please describe.

Yes. After #3002 was merged, we are now required to set explicit type definitions for every single axios request we make, even if we don't want to, because these would result in an error.

Describe the solution you'd like

The default type for AxiosResponse#data should be any so that we can modify it if we want, or keep it as is if we don't care about the typings for that specific request

Describe alternatives you've considered

As suggested in that PR, we could set the type to any explicitly, however, many people use typescript-eslint's no-explicit-any rule that prevents us from doing this. I believe everyone should be able to choose what types they wanna work with, because for extremely simple responses from which you only need one or two simple properties you don't always need explicit type declarations

Additional context

TypeScript's DOM library sets the return type of Body#toJSON to Promise, so we should be following the native approach and not restricting user's options by setting a default that "most users may want", even if most users do not want this.

@bratanon
Copy link

bratanon commented Oct 5, 2021

+1 for this.

@tjhorner
Copy link

tjhorner commented Oct 5, 2021

This seems related to #4109

@remcohaszing
Copy link
Contributor

Is your feature request related to a problem? Please describe.

Yes. After #3002 was merged, we are now required to set explicit type definitions for every single axios request we make, even if we don't want to, because these would result in an error.

It’s easy to specify the response data should be any.

const { data } = axios.get<any>('/');
// data is now any

I asked on the TypeScript Discord: Lets say you have a TypeScript function which could return anything, for example a library for making HTTP requests. The return type can be configured using a generic for convenience. Which would be the preferred default return type? any or unknown?

Everyone immediately responsed unknown. It was also unanimous that my choice of using never at the time was wrong. I agree with this now. Also unknown is now supported in the oldest supported versions of TypeScript supported by DefinitelyTypes, which wasn’t the case at the time of that PR.

Describe the solution you'd like

The default type for AxiosResponse#data should be any so that we can modify it if we want, or keep it as is if we don't care about the typings for that specific request

It’s easy to reduce type safety by specifying the response data is any, but it’s not possible to enforce strictness if the default is any

Describe alternatives you've considered

As suggested in that PR, we could set the type to any explicitly, however, many people use typescript-eslint's no-explicit-any rule that prevents us from doing this. I believe everyone should be able to choose what types they wanna work with, because for extremely simple responses from which you only need one or two simple properties you don't always need explicit type declarations

This really confuses me, as it seems to contradict your own point. You want to disallow the literal of any in your code base, but you do explicitly want to use an implicit any value by making axios not adhere to this rule.

Additional context

TypeScript's DOM library sets the return type of Body#toJSON to Promise, so we should be following the native approach

What exact API do you mean by Body#toJSON?

and not restricting user's options by setting a default that "most users may want", even if most users do not want this.

I don’t think the user’s options are restricted. They can use any if they want to.

Although in my experience TypeScript users prefer type safety over any values, I agree I don’t have the numbers to show for this or the opposite. However, the TypeScript documentation recommends to avoid the use of any

@simllll
Copy link

simllll commented Oct 6, 2021

I don't get this type at all, why is input and output the same data?

post<T = never, R = AxiosResponse<T>>(url: string, data?: T, config?: AxiosRequestConfig<T>): Promise<R>;
post return value is Axiosreponse<T> and data to pass into is also T? Who sends the exact same data structure to a server and gets the same result? Well there are some csaes I guess, but not very common in my opinion ;-)
Input/request and output/return data should be defined seperatly.

Edit: I just found #4109 (comment) .. (y) please get axios in good shape again. Thanks :-)

@remcohaszing
Copy link
Contributor

remcohaszing commented Oct 6, 2021

I want to clarify that #4109 is unrelated to this issue. Linking them to each other is confusing.

@simllll
Copy link

simllll commented Oct 6, 2021

I want to clarify that #4109 is unrelated to this issue. Linking them to each other is confusing.

You are right, setting it to any is just the only solution to the issue with same input/output type right now. Therefore they are at least "similar" for people who are looking for the issue ;-) And the title still refers to a similar issue: it's a breaking interface change. Something that was any before, is now something that needs to be defined. This breaks a lot of code base.

@jasonsaayman
Copy link
Member

Closing as the issue will be reverted in 0.23

@tjhorner
Copy link

tjhorner commented Oct 9, 2021

@jasonsaayman Do you have an idea of when 0.23 is slated to be released on npm? 0.22 fixes a bug that was affecting us but introduces this, so we can't use it. Right now we're just using a forked version of 0.22 with fixed types, but I'd much rather use the official version 😅

@simllll
Copy link

simllll commented Oct 9, 2021

The unknown type is still a breaking change in master,

If you are looking for alternatives I really can recommend gaxios (which is based on fetch, therefore http/2 etc is supported) or I also just created haxios which is a wrapper on gaxios but extends the interface to be more identical to the original axios.. haxios is still in a very early stage though.

@ImRodry
Copy link
Contributor Author

ImRodry commented Oct 13, 2021

Closing as the issue will be reverted in 0.23

Was this a lie or what?? Reverting doesn’t mean changing the type to unknown…

@jasonsaayman
Copy link
Member

@ImRodry please open a pull request if you still have an issue with the way types are handled. Also note that should you continue to not follow our code of conduct I will be forced to ban you.

Thanks

@ITenthusiasm
Copy link

ITenthusiasm commented Oct 13, 2021

Is this the right place to continue the discussion @jasonsaayman ? (If not, could I be directed on what to do next, eg. open a new issue? 😅)

I have mixed feelings about this. Personally, I'm not a big fan of the change to unknown.

unknown is more type safe...

But I agree with @remcohaszing that it's more type safe... which is why I'm not surprised that the participants in the TS Discord discussion said to prefer unknown to any. It's just the de facto standard these days. So... there's some legitimacy there.

...but any is arguably friendlier

I think any is friendlier to the developer in the end. Looking at @remcohaszing's proposed question:

Lets say you have a TypeScript function which could return anything, for example a library for making HTTP requests. The return type can be configured using a generic for convenience. Which would be the preferred default return type? any or unknown?

I wasn't part of that discussion, but I tried to skim it briefly (very briefly 😅). And unsurprisingly, I mainly saw the immediate response that I think most (and good) TS developers have: "Avoid any and unknown at all costs! We can't avoid any? Oh no! Well we have to use unknown then!" I also have this immediate response (though I'm not claiming to be a great TS dev. lol.)

In that discussion (which did not involve that many participants), I didn't see much talk about developer experience. And since axios is a library, this is something very important to consider. This discussion isn't only about whether or not our types should be "incomparably pure"; it's also about the impact on users.

When the return type is changed from any to unknown, it forcibly shoves all of the type responsibility to the developer -- even if they don't want it. "What TS dev wouldn't want types?" one may ask. Let me explain.

Example 1

Please consider one of my repositories, which is now failing on CI after updating axios. Particularly, look at this code, which is now failing. My code attempts to interact with the PodBean API for podcast stuff. The API is a bit strange, the docs aren't the best, and sometimes the docs take a long time to load. PodBean exposes no "types library", so when the return type from axios is unknown, the responsibility is on me to create all of the individual types in my own repository, even though they may be subject to spontaneous change. Not only that, but I then have to cast all of my interactions with data to these created types to do anything with data in TS. In addition to being inconvenient and time consuming, this runs the risk of my formatter making one-line statements become multi-line statements, increasing LOC. (I know, a reader can consider that trivial.)

This situation gets more complicated when it comes to error handling. Caught errors, by default, are unknown. This means that errors need to be casted or narrowed. Life is easier if the error is known to be the instance of a certain kind of class (instanceof type narrowing), but I'm assuming AxiosError is an interface instead of a class, meaning instanceof narrowing is impossible. So, any time I want to interact with the AxiosError object, I first have to cast err to AxiosError. But after that, I have to do more type casting for data. This quickly results in unwieldy code that becomes difficult to read. I can't even re-throw AxiosError or AxiosError.response?.data as is, because Error's constructor in TS expects a string (even though it stringifies the argument).

(Edit: I can rethrow err itself as is, assuming it wasn't cast to AxiosError. Similar story with the data prop.)

Now sure, any individual can decide if they want to die on the hill of "supremely pure types" if they want. But once code starts getting this inconvenient, I personally feel it's unfair to force this situation upon the consumer.

Example 2

(If you're already convinced, you can skip this part. Unless you're curious for more info.)

Another example to consider is React JSS, a library for styling React components. As you can see in the example code from the link, the library enables developers to write CSS in JS. Thankfully, it enables devs to style components based on props. But the problem is that the library doesn't know what the props will be in the defined function. Things were ultimately figured out by aggressively trying to use generic types, but let's say that, for the sake of argument, they had to choose only between any and unknown.

unknown would be more "TS proper", but any would be vastly more developer friendly. Why? These CSS declarations can get quite long, and they'll likely scale depending on the size of the component. (And not all components can be made tiny.) If the argument of the callback was typed as unknown, then the developer would be forced (keyword) to explicitly define the type for every single callback, even though the type of props would already be made clear in another part of the file. This results in redundancy across several lines. If the argument of the callback was typed to any, then the developer has the choice (keyword) of whether or not they want to endure said redundancy.

Final "evidences", no examples

I can understand encouraging devs to use unknown for their own personal functions. But I personally don't understand the purist push for using unknown over any when libraries are involved. I guess I could agree that in some cases it protects the user. And known types are always preferred. But when any and unknown are literally the only options, then in many cases, I think unknown causes more problems. Whether a developer is given an any value or an unknown value, they are left with the same problem: The developer who wants good, safe types has to explicitly type cast, type narrow, etc. When it comes to libraries, this means that any satisfies the most users: 1) For the purists, they still have the option to type cast (which they'd be forced to do with unknown anyway), 2) For the semi-purists who like types but want code that's more readable in their eyes, they have the option to be freed from inconvenient type casting. The decision should be given to the consumer.

And as a very minor tidbit, I think people like myself also like being given anys over unkonwns from libraries (when those are the only options) because it means we can get to keep our "neat code" without having to battle TS ESLint. (The suggestion for the user to use <any> as a generic type argument will make lint unhappy.) That's admittedly lazy though. 😅

Lastly, regarding that Discord conversation, the one who seemed to contribute most was 𝚠𝚎𝚋𝚜𝚝𝚛𝚊𝚗𝚍, and I have to agree with his last statement:

but if you have to stick with any for backwards compatability, I'll just suffer
it's not the end of the world

I think that's the wiser approach here. Even the native fetch API returns Promise<any> for response.json(). I imagine this is again for the developer experience -- as, practically speaking, nothing is gained for the consumer of a library when any is changed to unknown, but much is lost.

Open to different ideas. I know I said a lot.

@jasonsaayman
Copy link
Member

@ITenthusiasm thanks for your long and explanative examples above. Point taken. Honestly TypeScript in Axios is very much something that has been bolted on and is not at the core of how the library functions, in fact the index.d.ts was only added if I can remember to satisfy typings being visible to consumers.

With that being said, I felt that using unknown would have been better than any, this was to be an enhancement and not a regression, and in fact something I thought may be very helpful to people using TypeScript. If the experience is now degraded as you have mentioned above I think it would be best to investigate reverting back.

@remcohaszing I would like to get your opinion on this too if possible?

@jasonsaayman jasonsaayman reopened this Oct 13, 2021
@ITenthusiasm
Copy link

ITenthusiasm commented Oct 13, 2021

Honestly TypeScript in Axios is very much something that has been bolted on and is not at the core of how the library functions, in fact the index.d.ts was only added if I can remember to satisfy typings being visible to consumers.

I get that. I think React JSS ran into a similar issue too. This is the really hard part of awesome libraries like axios and jss having to deal with the expanse of typescript after the fact. Looking forward to @remcohaszing's opinion too.

Thanks for re-opening!

@remcohaszing
Copy link
Contributor

remcohaszing commented Oct 13, 2021

The various TypeScript related changes in axios 0.22.0 has left many users confused. Mostly because it included some bugs, making axios unusable. These bugs are unrelated and shouldn’t be confused with the discussion of any vs unknown.

Also the change from any to never was wrong. I proposed that change over a year ago and didn’t expect this suddenly to be merged. The change from never to unknown was a fix for this.

Now that most type related bugs in 0.22.0 have been fixed, I feel like this is a proper time to discuss this.

First of all I would like to point out this issue is highly subjective, but there are some arguments to make for selecting either default. The change has received both positive and negative feedback.

I agree this is about developer experience, but at a different level. Given the replies so far, it has become clear different people have different opinions about what a good developer experience means. Personally I like the added type safety: it has already helped me catch a small bug.

The reason I think that unknown is the better choice when making this tradeoff, is that’s is relatively simple to drop the type safety by explicitly passing any as a generic, but when the default is any, it’s easy to forget to narrow down the type. The TypeScript option noImplicitAny can be used to disallow implicit any types. The ESLint rule @typescript-eslint/no-explicit-any can be used to disallow explicit use of any in a code base. The axios generic default is explicitly defined as far as TypeScript is concerned, but it’s not literally defined in user code, meaning ESLint won’t report it either.

Let’s say we have the following code

const { data } = await axios.get('/user');
console.log(user.name);

Users who prefer data to be typed should add change this to the following:

const { data } = await axios.get<User>('/user');
console.log(user.name);

If data is any, no automated tool will warn the developer about the type unsafety. If data is unknown, TypeScript will warn the developer about this type unsafety.

If the developer prefers to opt-out of type safety, they can still do so, even if the default type is unknown.

const { data } = await axios.get<any>('/user');
console.log(user.name);

As for keeping ESLint happy, I feel that using unknown over any helps accomplish the goal of the rule that gets triggered, which is:

This rule doesn't allow any types to be defined. It aims to keep TypeScript maximally useful. TypeScript has a compiler flag for --noImplicitAny that will prevent an any type from being implied by the compiler, but doesn't prevent any from being explicitly used.

A linter should help increase code quality by making code adhere to a code standard. If for a project the choice was made to decrease type safety by allowing the use of any, that’s fine, but I don’t think that rule should be enabled then.


Lastly, regarding that Discord conversation, the one who seemed to contribute most was 𝚠𝚎𝚋𝚜𝚝𝚛𝚊𝚗𝚍, and I have to agree with his last statement:

but if you have to stick with any for backwards compatability, I'll just suffer
it's not the end of the world

This statement was about preferring any over never. This wasn’t about preferring any over unknown.


Side note about the AxiosError check: Axios has a helper function for this, so casting can be avoided:

try {
  // …
} catch (err) {
  if (!axios.isAxiosError(err)) {
    throw err;
  }
  // TypeScript knows err is an instance of AxiosError at this point.
}

@ITenthusiasm
Copy link

ITenthusiasm commented Oct 13, 2021

I'll handle the quoted responses last.

I agree that this is a subjective topic. But it's for that very reason that I don't find the use of unknown fair. The more subjective an issue is, the more logical it is for the provider to give more options to the user, not restrict them. When I'm talking about developer experience, I'm talking about all developers' experiences and the inconveniences that are brought about. And from what I can see, the inconvenience potentially brought to the "type purists" (as I've called them so far) is much smaller than the inconvenience brought about to everyone else.

That is, I'm not just evaluating preferences and positives. I'm evaluating negatives.

Type purists will already be using the type casting that would be forced by returning unknown for data. And while possible, it's much less likely for the type purist to forget to add the type to the response. They'll either add it immediately, or they'll notice it when they aren't getting the intellisense they want. Lacks of types can also be seen by reviewing code before committing and merging. Most bugs will probably be seen from code that was previously written badly.

The rest of the users are significantly more inconvenienced. If you read my earlier statement, you'll see that there can easily be scenarios where a person does not have access to officially defined types (or DT types). And these scenarios, especially when working with simple props like ImRody mentioned, result in unnecessary effort. We have to create more files/types, and we have to type cast everywhere. It's also important to remember that changing to unknown right now unnecessarily breaks backwards compatibility as far as TS is concerned (I'm ignoring the intermediate never). axios has more downloads than express, and the fixes for this breaking change are not as simple as would be found for, say, a change to React JSS's types. (This is because of, again, all the different files/types that have to be created, followed by the various type casts in different lines.)

It's also worth considering that the common standard for native APIs has been to use any when an unknown data type is being returned. This has held for fetch's response.json() and JSON.parse(), amidst other functions. When weighing inconvenience on a scale for everyone, it's clear how much more inconvenient it is to use unknown.

Considering that the type was previously any, there's no sufficient reason to spontaneously shift it to unknown, especially given the inconveniences it causes. There is reason to spare the devs before they get trapped up in these breaking changes.

Quoted Responses

Lastly, regarding that Discord conversation, the one who seemed to contribute most was 𝚠𝚎𝚋𝚜𝚝𝚛𝚊𝚗𝚍, and I have to agree with his last statement:

but if you have to stick with any for backwards compatability, I'll just suffer
it's not the end of the world

This statement was about preferring any over never. This wasn’t about preferring any over unknown.

I doubt that, since the Discord user was encouraging the use of unknown. I don't think he was ever suggesting never to begin with. This is further suggested by the statement that followed what I quoted.

I usually do whatever<unknown> anyway

Going from any to unknown counts as a breaking change.


Thanks for the axios.isAxiosError note. 🔥

@ITenthusiasm
Copy link

ITenthusiasm commented Oct 13, 2021

To touch further on that breaking changes note...

For comparison today:

Library Weekly Downloads
axios 21,505,469
typescript 22,719,100

Very close, with TS being slightly larger.

Even TS devs have times when they acknowledge previous decisions that were probably mistakes. But even then, they consider the impact of a breaking change on existing users. (Not that there are never breaking changes, of course. Value, ease of fixing, how many benefit vs how many get bitten, and more come into play.)

Though related to whether or not we should go back to any, this is separate from the discussion on enhancing developer experiences, and is also worth considering in its own right on the topic. The codebase I gave is small and will already require some inconvenient work if we go with unknown. For codebases more largely using axios, this breaking change could be quite large.

@orta
Copy link

orta commented Oct 13, 2021

👋🏻 I got pinged about this issue as I generally have to think about this sorta stuff for the DOM APIs which have similar impact scales for changes (4.4 was a particularly rough transition)

I generally side on any for something which is predominantly out of the control of the author. Yes, people are using TypeScript and expect a tighter type system setup - but at this scale most of the people writing TypeScript probably didn't set up their projects and environments (e.g. there's 1 person on the team setting all this infra up, the rest are tagging along and agree with most of the decisions) and using unknown makes their lives hard (and makes people think they're forced into doing extra TS ceremony)

It's a set of trade-offs and tensions. If it came out as axios v2, I think that sort of change would be seen as more reasonable - but for a point release I don't think folks would expect this sort of change (and yeah, I get the irony with TS' semver too)

IMO, cases like this (as with fetch, and JSON.parse) are a good examples of the need for a third bottom primitive which can act as any by default, and unknown when people want a more strict type system. We've felt the need in the DOM, in DT and in the main libs shipped with TS. I have a rough idea for how that could work which I'll spec out on the TS repo and you'll see linked below in a bit

@remcohaszing
Copy link
Contributor

The change was made from version 021.0 to 0.23.0 (The types in 0.22.0 were very broken, so let’s ignore those). As far as can tell from semver and the axios upgade guide, it’s ok to make breaking changes.

If the Axios team disagrees with this, I definitely think the default type should be reverted to any. Otherwise at I think this change should at least be documented in the migration guide.

/cc @jasonsaayman

microsoft/TypeScript#46347 looks very promising. That would end this discussion and similar discussions for other libraries with a compiler setting. If that get’s implemented, the correct type wouldnt be any nor unknown, but any | unknown of which the behaviour could be changed by the user. For now this matches any.

I think all arguments have been made. Ultimately the choice is up to the Axios team.

@ITenthusiasm
Copy link

I'm also interested in the issue orta created.

Since it may take some time until that suggestion gets approved, developed, merged, and released, my vote is for switching back to any now, and waiting for microsoft/TypeScript#46347 to come to fruition. @ImRodry has already created a PR to that end. This prevents any unnecessary harm from being thrust upon developers currently using axios (as previously mentioned), and it looks forward to a brighter future where both sides of concerns are resolved.

From what jasonsaayman said, it seems that the hope was to benefit the consumers of the axios library overall. I can say that the bite of the switch from any to unknown is felt, even in a small repo. So reversion is worth considering. Orta made some good points. I don't have anything else to add.

@ITenthusiasm
Copy link

ITenthusiasm commented Oct 13, 2021

Well, there's one more thing I missed. 😅

As for clarity on this statement:

The reason I think that unknown is the better choice when making this tradeoff, is that’s is relatively simple to drop the type safety by explicitly passing any as a generic

The problem that ImRody and I mentioned is that passing any as a generic type causes problems when using TS ESLint, as I mentioned earlier. That's why it's not a valid solution still. (Writing eslint-disable for every call with axios is impractical.)

Many people got confused about ImRody saying he didn't want to use generic anys, but also preferring any for data. This is probably what ImRody was getting at.

All that to say, using any as a generic type argument won't work here. It likely won't work when casting err to AxiosError either.

A linter should help increase code quality by making code adhere to a code standard. If for a project the choice was made to decrease type safety by allowing the use of any, that’s fine, but I don’t think that rule should be enabled then.

This applies for users writing their own code. But again, the situation is different when it involves a library and consumers. Consumers like ImRody and I do like to have good types. I actually take types that I can control very seriously. And I even helped ReactJSS improve its types in the past. But as far as this discussion is concerned, axios's data is basically something similar to the return type of JSON.parse() and response.json(), as previously mentioned. So it's not quite the same as a consumer "intentionally decreasing type safety" since we're looking at how the library is taking responsibility for its consumers here.

@ImRodry
Copy link
Contributor Author

ImRodry commented Oct 20, 2021

So for those who want the type benefits of unknown, wouldn't the equivalent be possible?

Simply put, no, because the point of using unknown is to override it with a custom type, you can't even access or work with an unknown variable if it's explicitly typed as unknown. The same is also not possible/good practice in most projects due to linter rules that disallow the explicit use of any, as mentioned above

@remcohaszing
Copy link
Contributor

remcohaszing commented Oct 21, 2021

I see the suggestion:

It’s easy to specify the response data should be any.

const { data } = axios.get<any>('/');
// data is now any

So for those who want the type benefits of unknown, wouldn't the equivalent be possible?

const { data } = axios.get<unknown>('/');
// data is now unknown

I can see why you think this. The problem here is what any means.

Both any and unknown have the same semantic meaning: TypeScript doesn’t know the type of a value. This also means both are equally correct.

any means TypeScript saying: “I don’t know what this type is. Do with it whatever you want, but I can’t provide type safety.”
unknown means TypeScript saying: “I don’t know what this type is. Be careful how you use it.”

If the default is any, TypeScript will not provide any type safety for the data. Technically it’s possible to specify unknown, but TypeScript won’t warn the user if they forgot to specify the type as a generic.

If the default is unknown, TypeScript will warn the user that the type of data is unsafe to use by default. This means the user is reminded they should narrow down the type. In case of axios they need to specify a proper type generic (which could be any).

The TypeScript community is divided on this. Many similar libraries use any, but also many use unknown. The main thing that sparked this discussion isn’t the choice for any or unknown, but the fact that it changed.


I think a consumer could put that in a custom wrapper or utility method if they want it as the "default" for their project.

This is an interesting thought, but I doubt anyone wants to create an axios wrapper function just to change the default of the generic. Axios isn’t the only library which provides function that return any or unknown.

@jasonsaayman
Copy link
Member

I am unfortunately/fortunately (depending on where you allegiances lie) going to revert this back for now to use any rather than unknown. This is not an easy decision but it does seem to me that the use of any makes Axios more accessible right now. In the future this could change again, possibly when we cut a v1.

I want to thank everyone in this thread, it was pretty heated and a lot of people contributed quite a bit to this, all the opinions expressed are valued. I will cut a 0.24 to release this.

@bobvandevijver
Copy link

bobvandevijver commented Nov 2, 2021

Not to spark any discussion whatsoever, but I just wanted to let you guys know that I actually loved the change to unknown as that forced me to correct the typings on many places, resulting in better typed code.

I would love to see the unknown come back in a v1 release in the future (I already did the work anyways 😅), but I can understand that this change does not fit within the current v0 release. Even though you could discuss that a v0 is not stable (so changes like these can just "happen"), that is a whole other discussion 😄

@ITenthusiasm
Copy link

ITenthusiasm commented Nov 2, 2021

Yeah some kind of RFC leading up to v1 could be useful. (Or the discussion here could be re-used for data when v1 comes along too, I suppose. 🤔) If microsoft/TypeScript#46347 gets addressed in time, it may not even need to be a big discussion.

@paulnelson2
Copy link

paulnelson2 commented Nov 3, 2021

So it's not a sure thing that v1 will have unknown?

In that case, let me give my two cents:

I think unknown should be the default for data, and with all due respect to those discussing whether unknown or any is better, that's not the point. The point I think can be shown through a comparison:

  1. Default unknown -- In this situation, those who prefer unknown have no work, and those who prefer any will be told by Typescript in each and every place that they need to change to any, and then they can do so.
  2. Default any -- In this situation, those who prefer unknown will never be informed by Typescript where they need to change things. Naturally, those who prefer any have no work to do.

In summary, (1) results in visible problems for some people, and (2) results in invisible problems for some people. Some people are going to have problems either way. I would argue that causing users visible problems is better than causing users invisible problems and that therefore (1) default unknown is the best choice.

That being said, I'm happy to wait until v1 cuz breaking changes.


@KosnIre

I see the suggestion:

It’s easy to specify the response data should be any.

const { data } = axios.get<any>('/');
// data is now any

So for those who want the type benefits of unknown, wouldn't the equivalent be possible?

const { data } = axios.get<unknown>('/');
// data is now unknown

The problem is that those who want to do axios.get<any> will be told by Typescript where they need to make changes, but the people who would want axios.get<unknown> won't be told.

@cgarrovillo
Copy link

TypeScript is only as good as the developer that uses it. Per the official TypeScript docs regarding the use of any:

any
❌ Don’t use any as a type unless you are in the process of migrating a JavaScript project to TypeScript. The compiler effectively treats any as “please turn off type checking for this thing”. It is similar to putting an @ts-ignore comment around every usage of the variable. This can be very helpful when you are first migrating a JavaScript project to TypeScript as you can set the type for stuff you haven’t migrated yet as any, but in a full TypeScript project you are disabling type checking for any parts of your program that use it.

In cases where you don’t know what type you want to accept, or when you want to accept anything because you will be blindly passing it through without interacting with it, you can use unknown.

And from the beginning of the thread:

because for extremely simple responses from which you only need one or two simple properties you don't always need explicit type declarations

If it is so simple, why not just declare the types? That just sounds lazy and incompetent.
What is the point of using the TypeScript language at all if you're choosing to deliberately go back to JS using any? I am all for developer experience, and I get any will be the easier route always.

But on the same coin, failing to provide types just results in technical debt, a future debt repaid when a new developer comes on to the project and works with the axios logic written by someone who didn't want to take a few minutes to declare the types of "extremely simple responses".

@popuguytheparrot
Copy link

popuguytheparrot commented Dec 24, 2021

Types not fixed yet

   Object is possibly 'undefined'. 
   59 | RequestHttp.interceptors.request.use((config) => {
    60 |     const token = JwtTokenLocalStorageService.getParsedAccessToken();
  > 61 |     config.headers.Authorization = token ? `Bearer ${token}` : '';
       |     ^

@ImRodry
Copy link
Contributor Author

ImRodry commented Dec 24, 2021

@popuguytheparrot that issue is completely unrelated to the original issue reported here

simplesmiler added a commit to simplesmiler/taxios that referenced this issue Jul 31, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.