If I return a wider type, I am not lying. I am preventing consumers from depending on my implementation instead of the contract. The contract leaves me room to tweak my implementation. Inferred types may not.
The amount of type guards consumers have to do since the type is wide makes the code messy and indented, it again largely depends but in most of the codebases which uses enums(or objects as enums) it’s better to strictly infer it. These are very subjective, and varies from function to function, I do agree with it
I'm dealing with this right now where I have a function that registers an input component by returning some props. I could explicitly say which props will be returned, but that, as you say, would potentially have people depend on implementation details instead of just knowing that some props compatible with an input are returned.
Conceptually, specifying a type makes sense to me. It forces me think about how I want this function to work. To think about the function as a black box, where I get something and I return something else. How I accomplish it is second to how that function is an important piece of a big machine.
Infer, I catch more bugs when things use the result in an incorrect manner. I only type when I want to enforce a return type into the right shape no matter the path, otherwise infer catches when the rest of my program is broken.
No debate, infer is just better if functionality is forwarding schema. Or you may end up changing schema for complex api beforehand, just an extra step.
Specify the return type +1. More readable, more consistent, more reliable, more everything. But anyway you can choose what’s fit better for you, you’re free to choose and that’s the problem.
I work in a team. We require it so people dont have to guess between what should be returned and what is being returned. Not everyone knows every single line of code, and in 6 months time, i wont remember it either. What if my function returns a result of another function, and then later down the line that function changes return type. I dont want it to blindly accept whatever is goinf to happen now, i want people to KNOW the consequences of their refactor. Typescript would report the error in the wrong place otherwise. Saying the mistake is maybe 3 levels higher than it should be, rather than nipping it right at the source. No need ro go hunting for stuff then Yes, if the deep deep function SHOUKD be returning a new type, it does mean you need to refactor in more places all the way up, but boohoo for you. At least its clear how much of an impact this "little" change is going ro have.
Explicit return types are most helpful when a function conditionally chooses among multiple return statements. The declaration can help ensure they're all consistent at the appropriate level of abstraction. I definitely add them whenever the system infers a type I didn't expect/intend. I'd say I use inferred return types for ~98% of functions, though. It just reduces the mechanical cost of maintaining the codebase and doesn't really hurt quality of you've got the right 2% covered.
This strikes me as disingenuous. A linter doesn’t force people to do anything. It just makes doing the wrong thing a little bit harder. You could have easily framed this discussion the other way around and said “Should we have guardrails, or should we let anyone do whatever they want whenever they want?”
Not entirely true. A lint rule can definitely force people to do it. You can definitely check lint rules in your CI and prevent a PR from being allowed to merge. There are also tools that you can configure in a project to prevent developers on their machine from doing a git commit if it does not adhere to some rules. Although I am not a fan of blocking git commits in this way. I would recommend doing in the CI.
I got into a problem of having a exhaustive types that take like 10m instantiations and using return types reduced it into 6k, and sped up the type inference on my code alot, maybe one of the reasons u might wanna use
@@azizsafudin With type inference types just describe implementation. If the types are wrong then the implementation is wrong. I don't need to debug types, only actual program logic. With hardcoded types you're just as likely to make a typing mistake as an implementation one, that leaves you with twice the things to debug.
@@mattpocockuk why???! Why would I do that? That is absurd. In my experience, without explicit return types, that is the kind of fn signature you can end up with when everything is inferred. In no other programming language do I write this kind of return signature and so why should I ever explicitly write this kind of nonsense in typescript, assuming I am not completely unaware of what domain modeling means?
For the record, I don’t have a strong opinion on this subject. Just calling out that you’re not making an argument so much as using tricky language here.
See, I'd say always put a return type on your functions - 'cus, then, if someone looks at it quickly and says "I wonder what type this function returns"... well, they don't have to say that at all 'cus there it is right in front of their eyes. ... ... ... except you're dead right about React.
@@mattpocockuk "Slow Types", "isolatedDeclerations". Source: Syntax Podcast - JSR: The New TypeScript Package Registry - 34:14... Would be interested in your thoughts on what he said :)
They're useful in some cases--usually when a function has multiple paths/branches/conditions where it can return similar but different complex structures. The explicit return type will help keep the statements consistent and e.g., flag cases where you forgot some property or transform or other. Requiring them is a bit heavy handed, though. In most cases, they just get in the way.
If you don't require it, people don't bother to add return types at all. Then what is the point of using typescript? Perhaps good old plain JS is better? With some jsdoc typing for your liking. Similar case goes to "any". You can allow it. Then whole project is full of 'any' types. Which again goes against typescript principles. So why bother using ts and having additional build step at all?
If you don't add it, typescript will figure out what the return type is and infer it from your code. And a lot of the time that's better, because it ensure the return type is actually true to what the code does, instead of what you think or want.
yep that’s the same issue at my work brand new project people says let’s use typescript but then just add any everywhere. If you don’t set the standard the standard will be “no standards”
@@mattpocockuk Ok. Other perspective: are types always infered with 100% accuracy ? I mean, if there is no difference between writing those types by hand and infering, then why TS team even bother to add this option at all ??
If I return a wider type, I am not lying. I am preventing consumers from depending on my implementation instead of the contract. The contract leaves me room to tweak my implementation. Inferred types may not.
I actually really like this take. This is excellent in a library setting. But in app code I usually just don't care.
The amount of type guards consumers have to do since the type is wide makes the code messy and indented, it again largely depends but in most of the codebases which uses enums(or objects as enums) it’s better to strictly infer it.
These are very subjective, and varies from function to function, I do agree with it
I'm dealing with this right now where I have a function that registers an input component by returning some props. I could explicitly say which props will be returned, but that, as you say, would potentially have people depend on implementation details instead of just knowing that some props compatible with an input are returned.
Conceptually, specifying a type makes sense to me. It forces me think about how I want this function to work. To think about the function as a black box, where I get something and I return something else. How I accomplish it is second to how that function is an important piece of a big machine.
Also if your function just wraps another function it's duplicated work, annoying if the inner function changes.
Infer, I catch more bugs when things use the result in an incorrect manner. I only type when I want to enforce a return type into the right shape no matter the path, otherwise infer catches when the rest of my program is broken.
I try to define explicit return types wherever applicable. It should be the default, just like all strict programming languages.
No debate, infer is just better if functionality is forwarding schema. Or you may end up changing schema for complex api beforehand, just an extra step.
Specify the return type +1. More readable, more consistent, more reliable, more everything. But anyway you can choose what’s fit better for you, you’re free to choose and that’s the problem.
I work in a team. We require it so people dont have to guess between what should be returned and what is being returned.
Not everyone knows every single line of code, and in 6 months time, i wont remember it either.
What if my function returns a result of another function, and then later down the line that function changes return type.
I dont want it to blindly accept whatever is goinf to happen now, i want people to KNOW the consequences of their refactor.
Typescript would report the error in the wrong place otherwise. Saying the mistake is maybe 3 levels higher than it should be, rather than nipping it right at the source.
No need ro go hunting for stuff then
Yes, if the deep deep function SHOUKD be returning a new type, it does mean you need to refactor in more places all the way up, but boohoo for you. At least its clear how much of an impact this "little" change is going ro have.
Even if you don't work in a team... you work in a team!.. There's "you", "you next month", "you next year", "you in a couple of years time"...........
Explicit return types are most helpful when a function conditionally chooses among multiple return statements. The declaration can help ensure they're all consistent at the appropriate level of abstraction. I definitely add them whenever the system infers a type I didn't expect/intend.
I'd say I use inferred return types for ~98% of functions, though. It just reduces the mechanical cost of maintaining the codebase and doesn't really hurt quality of you've got the right 2% covered.
Explicit return types can help sometimes with typescript performance.
This strikes me as disingenuous.
A linter doesn’t force people to do anything. It just makes doing the wrong thing a little bit harder.
You could have easily framed this discussion the other way around and said
“Should we have guardrails, or should we let anyone do whatever they want whenever they want?”
Not entirely true. A lint rule can definitely force people to do it. You can definitely check lint rules in your CI and prevent a PR from being allowed to merge. There are also tools that you can configure in a project to prevent developers on their machine from doing a git commit if it does not adhere to some rules.
Although I am not a fan of blocking git commits in this way.
I would recommend doing in the CI.
I got into a problem of having a exhaustive types that take like 10m instantiations and using return types reduced it into 6k, and sped up the type inference on my code alot, maybe one of the reasons u might wanna use
Compilers make mistakes far less often than people do, that's why I prefer to leave their work to them, including type inference.
Type inference just means the compiler is depending on your implementation for the type. The exact opposite to the point you’re making.
@@azizsafudin With type inference types just describe implementation. If the types are wrong then the implementation is wrong. I don't need to debug types, only actual program logic. With hardcoded types you're just as likely to make a typing mistake as an implementation one, that leaves you with twice the things to debug.
How does explicit === wider types? That statement does not compute in my head...
const returnsString = (): string | null | number | object => 'abc'
@@mattpocockuk why???! Why would I do that? That is absurd. In my experience, without explicit return types, that is the kind of fn signature you can end up with when everything is inferred. In no other programming language do I write this kind of return signature and so why should I ever explicitly write this kind of nonsense in typescript, assuming I am not completely unaware of what domain modeling means?
For the record, I don’t have a strong opinion on this subject. Just calling out that you’re not making an argument so much as using tricky language here.
See, I'd say always put a return type on your functions - 'cus, then, if someone looks at it quickly and says "I wonder what type this function returns"... well, they don't have to say that at all 'cus there it is right in front of their eyes.
... ... ... except you're dead right about React.
Thats IDE problem
I feel like if you have some core utils, you should type the return, given that the functions don't change very often.
Does having explicit return types make typescript faster, as it has less work to do?
Yes it does.
Nope, it still needs to check the function against the return type you provide.
@@mattpocockuk "Slow Types", "isolatedDeclerations".
Source: Syntax Podcast - JSR: The New TypeScript Package Registry - 34:14... Would be interested in your thoughts on what he said :)
I think it should be required, we are using typescript so use types.
elm is superior
I have a rule to always avoid return types, cause this
They're useful in some cases--usually when a function has multiple paths/branches/conditions where it can return similar but different complex structures. The explicit return type will help keep the statements consistent and e.g., flag cases where you forgot some property or transform or other.
Requiring them is a bit heavy handed, though. In most cases, they just get in the way.
If you don't require it, people don't bother to add return types at all. Then what is the point of using typescript?
Perhaps good old plain JS is better? With some jsdoc typing for your liking.
Similar case goes to "any". You can allow it. Then whole project is full of 'any' types. Which again goes against typescript principles.
So why bother using ts and having additional build step at all?
If you don't add it, typescript will figure out what the return type is and infer it from your code.
And a lot of the time that's better, because it ensure the return type is actually true to what the code does, instead of what you think or want.
yep that’s the same issue at my work brand new project people says let’s use typescript but then just add any everywhere. If you don’t set the standard the standard will be “no standards”
@@KhanhNguyen-hd7wsthat’s not even a fair comparison in any way at all.
Google *inference*
@@mattpocockuk Ok. Other perspective: are types always infered with 100% accuracy ? I mean, if there is no difference between writing those types by hand and infering, then why TS team even bother to add this option at all ??
No, this is horrible. This rule should be turned on for team projects. Other people here in the comment section explained it in greater details.