Be Careful With Return Types In TypeScript
Summary
TLDREl guion discute la controversia sobre el uso de tipos de retorno en TypeScript, argumentando que muchas opiniones comunes son incorrectas. Se presenta un ejemplo donde la inferencia de tipos sin especificar explícitamente los tipos de retorno resulta en una representación más precisa y verdadera del resultado de una función. El guion destaca cómo los tipos de retorno explícitos pueden 'mentir', ocultando o alterando la verdad sobre los datos que una función realmente devuelve. Se enfatiza la importancia de la verdad en la programación y cómo la inferencia siempre refleja la verdad, aunque sea más amplia, mientras que los tipos de retorno pueden ser engañosos y peligrosos si no se usan con precaución.
Takeaways
- 🔍 Evitar los tipos de retorno cuando sea posible puede ser beneficioso.
- 🤔 Los tipos de retorno estrictos pueden llevar a resultados inexactos y engañosos.
- 💡 Usar 'as const' en TypeScript puede proporcionar resultados más precisos.
- 🚫 Los tipos de retorno pueden mentir y causar errores difíciles de detectar.
- 📊 Diagrama: La inferencia de tipos a menudo da la verdad, incluso si es más vaga.
- ⚠️ Ejemplo de 'getUser': La inferencia de tipos incluye 'password', mientras que un tipo de retorno lo omite erróneamente.
- 🔄 Sobrecarga y tipos de retorno: Pueden dar resultados incorrectos si no se manejan adecuadamente.
- 📝 La inferencia de tipos es más segura y cercana a la verdad en la mayoría de los casos.
- 🌐 El consenso general entre los expertos es preferir la inferencia de tipos.
- 💬 Comentarios de expertos: La mayoría prefiere la inferencia de tipos por su precisión y seguridad.
Q & A
¿Por qué es importante discutir cómo se deben escribir las funciones en TypeScript?
-Es importante porque hay muchas opiniones erróneas sobre cómo se deben escribir las funciones, y entenderlo mejor puede mejorar la calidad y la seguridad del código.
¿Qué es un 'contrived inferred example' y por qué se utiliza en el script?
-Es un ejemplo artificial creado para ilustrar un concepto específico, en este caso, para demostrar cómo TypeScript infiere tipos sin especificarlos explícitamente.
¿Por qué se recomienda evitar los tipos de retorno en ciertos casos según el script?
-Se recomienda evitar los tipos de retorno cuando se pueden inferir correctamente por TypeScript, ya que los tipos inferidos pueden ser más precisos y revelan la 'verdad' sobre lo que realmente se está devolviendo.
¿Qué es 'as const' y cómo afecta la inferencia de tipos en TypeScript?
-'as const' es una forma de hacer que TypeScript trate los valores como constantes en lugar de como tipos más genéricos, lo que puede resultar en un tipo más estricto y preciso.
¿Cómo se puede usar la inferencia de 'as const' para mejorar la precisión del tipo de retorno de una función?
-Al usar 'as const', TypeScript garantiza que el tipo devuelto sea exactamente el resultado de la función, sin ambigüedades ni generalizaciones innecesarias.
¿Por qué pueden ser los tipos de retorno considerados como 'mentirosos' según el script?
-Los tipos de retorno pueden ser considerados 'mentirosos' porque a veces no reflejan con precisión lo que realmente se está devolviendo, lo que puede llevar a errores o malentendidos en el código.
¿Qué es un 'diagrama de tipos' y cómo se utiliza en el script para ilustrar un punto?
-Un 'diagrama de tipos' es una representación gráfica que muestra las relaciones entre diferentes tipos posibles y la 'verdad' del tipo real. Se utiliza para ilustrar cómo las diferentes soluciones se relacionan con la 'verdad' y cuánto se alejan de ella.
¿Qué ejemplo se utiliza para mostrar cómo los tipos de retorno pueden 'mentir' en el caso de un objeto 'User'?
-Se utiliza un ejemplo donde una función 'getUser' devuelve un objeto 'User' con un campo 'password' que no debería estar presente, pero que se incluye en el tipo de retorno, lo cual es incorrecto y puede causar confusiones.
¿Qué es 'getUser override' y cómo puede ser problemático según el script?
-'getUser override' es una forma de especificar un tipo de retorno específico para una función sobrescrita. Puede ser problemático porque puede inducir a errores al no reflejar correctamente los valores que se están devolviendo.
¿Por qué se sugiere ser cauteloso con los tipos de retorno y cómo se puede mejorar la inferencia de tipos?
-Se sugiere ser cauteloso con los tipos de retorno porque pueden contener información incorrecta o incompleta. Para mejorar la inferencia de tipos, se puede confiar en la inferencia de TypeScript por defecto y utilizar 'as const' cuando sea necesario para una precisión más estricta.
Outlines
🤔 Evitar tipos de retorno en TypeScript
El primer párrafo discute la polémica sobre cómo se deben escribir las funciones en TypeScript, y cómo muchos de los prejuicios son incorrectos. Se argumenta que, en algunos casos, deberíamos evitar los tipos de retorno. Se da un ejemplo de una función que devuelve un objeto con un estado y un valor, y se muestra cómo la inferencia de tipos sin especificar explícitamente el tipo de retorno puede resultar en un tipo más preciso. Además, se compara con el uso de 'as const' para obtener una inferencia más estricta y se concluye que, en algunos casos, los tipos de retorno pueden ser menos precisos que la inferencia por sí sola.
😕 Las limitaciones de los tipos de retorno
En el segundo párrafo, se profundiza en los problemas de los tipos de retorno, como la facilidad con la que pueden 'mentir' o no reflejar la verdad sobre los datos que se están manipulando. Se presenta un ejemplo donde el tipo de retorno está mal definido y cómo esto puede llevar a errores en la comprensión de los datos que se están devolviendo. Se argumenta que los tipos de retorno pueden ser menos precisos y cómo la inferencia pura puede ser una alternativa más fiable. Se utiliza un diagrama para ilustrar cómo la inferencia y los tipos de retorno se relacionan con la 'verdad' subyacente de los datos involucrados.
🚫 Contraargumentos y consideraciones finales
El tercer párrafo ofrece una reflexión final sobre el uso de tipos de retorno en TypeScript. Se mencionan ejemplos de cómo los tipos de retorno pueden ser problemáticos y cómo la inferencia puede ser una solución más segura y precisa. Se argumenta que, en la mayoría de los casos, la inferencia es suficiente y que deberíamos ser cautelosos al introducir tipos de retorno explícitos. Se sugiere que, si se necesita un tipo de retorno específico, debería haber una documentación clara para advertir sobre la facilidad de 'mentir' con ellos. Se concluye con la preferencia de varios desarrolladores por la inferencia en lugar de los tipos de retorno explícitos.
Mindmap
Keywords
💡Tipos de retorno
💡Inferencia de tipos
💡Const
💡Diagnóstico de errores
💡Ejemplos contrived
💡Diagramas
💡Mentiras en el sistema de tipos
💡Sobreescritura de tipos
💡Ejemplos de código
💡Evitar tipos de retorno
Highlights
存在许多关于在TypeScript中如何编写函数的观点,但许多观点是错误的。
讨论了避免在TypeScript中使用返回类型的情况。
示例展示了在函数中不使用返回类型,TypeScript会如何推断类型。
使用as const可以更严格地推断类型,因为它将值视为常量。
使用as const可以保证获得准确的结果类型。
添加返回类型可能会覆盖更精确的类型推断结果。
通过图示解释了类型定义与实际返回值之间的关系。
类型定义的目标是尽可能接近实际返回值的真实类型。
返回类型可能包含谎言,因为它们可能不完全反映函数的实际返回值。
使用类型推断可以避免在类型定义中撒谎。
示例展示了如何通过返回类型覆盖实际返回值,导致类型定义不准确。
讨论了类型守卫和类型覆盖的问题,以及它们如何可能导致错误的类型定义。
使用类型覆盖可能会隐藏函数实际返回的额外属性。
讨论了typescript中的类型守卫和类型覆盖的潜在风险。
提出了一个类型覆盖的例子,该例子在直播中看起来有效,但后来被发现是完全错误的。
强调了在TypeScript中使用类型覆盖时需要非常小心,以避免类型定义与实际返回值不一致。
建议在大多数情况下使用类型推断,除非有特定的性能考虑或需要明确指定类型。
强调了在TypeScript中使用类型推断的重要性,以及它如何帮助保持代码的真实性。
多位TypeScript专家分享了他们对于使用类型推断还是显式返回类型的看法。
讨论了在TypeScript中使用类型推断的普遍性和其优势。
呼吁在TypeScript中默认使用隐式返回类型,除非有特殊情况。
视频结尾提出了结束关于TypeScript类型定义的争论的希望。
Transcripts
turns out there's a lot of opinions on
how to type your functions in typescript
and it turns out a lot of those opinions
are wrong this convo has been fun but
it's time to end it let's talk about why
you should avoid return types when
you're able to in this example we have a
result type the result is the thing we
get back from this function a result has
a status which is either OK or error and
it has a value or an error if the status
is error and this contrived inferred
example we're not passing a return type
which means this type isn't being used
and the result is that the type that we
get back has a value that is either
string or undefined even if we check and
confirm status is okay what we're
getting back here is this weird Tuple of
status during values during error
undefined or status string error error
value undefined and that's not a great
representation of the types going on
here if we give this a strict type by
putting a type definition at the end of
the function def like I have here then
we'll see with this contrived example we
now know confidently that value is
string after confirming the status is
okay this seems like a pretty obvious
compelling example of when you would
would want to use return types right
told you we could do better because I
think we can
this next example is using as const
because in this example there is a set
of values that are and aren't valid and
as const basically tells typescript
don't treat the things in here as
strings treat them as constants you'll
notice we get something even more strict
that's interesting we get back yay why
are we getting back yay here well the
only two things this can actually return
are status OK value yay or status error
error error because of that the true
type of this function is status okay
value yay or status error error new
error and when you use as const with
inference without the type definition
you're guaranteed the correct result
like the exact correct result the actual
truth of what's being done and being
returned funny enough if you add back
the return type on here it actually
overrides the truth with a more vague
result and you'll see here in space is
far enough
now the result now is that value is
string even though we know value is yay
because the as const gets overridden by
the thing you put here you all know
anything about me you know I love
diagrams so obviously I was going to
throw this in a diagram I have a key
here with the four things that will be
visible in any given piece I drew a
circle which is all the potential types
we could reasonably think result might
be it's our goal as developers to narrow
that type definition down to its very
core of the truth
so in this diagram I have the potential
as a black circle on the outside and I
have the truth as this little green
circle on the inside we're trying to
figure out how these different solutions
relate to the truth if we take the same
code the result the values type is EA
the raw inference does not give us yay
it doesn't even give us string it gives
us string or undefined which means the
types that it could potentially be are
large return types narrow it slightly as
we see here because return type knows it
has to be a string so in this case the
type is more narrowed it's closer to the
truth and then we have in the center
here cons d a because if you as const
these with constant inference
the result is the exact truth the exact
thing that we're getting back here
guaranteed thankfully in this example
all of the different options contain the
truth which means we're bickering over
the scope of what exists outside of the
truth here and I understand I can
totally see why people would not want
this area to exist and if they could
avoid it would choose to but what if I
told you it wasn't that simple
what if I told you
return types can lie I think lies are
the root of all evil and type systems I
prefer vagueness to not telling the
truth and with inference you can't lie
with return types it's trivial to lie
and it's even pretty easy to
accidentally let lies slip through code
review the first example I have here
comes credit Julius one of the lead
maintainers and creators of create T3
app Julius made an example that comes
close to my heart because I've made
mistakes like this before where we have
a user type that has a username and
email and notably it doesn't have a
password because this is meant to be the
user that we return to a user when they
make a request on our application
however if we have a function get user
that returns things that it shouldn't
like in this case a password this type
is not representative of what this
function returns and if we don't give
this function a type and we call it and
we get the response we see the inferred
responses or we see that the type that
we get back is correct it's username
email and password it knows that we have
the password here because we returned it
so obviously that's going to appear in
the typed result
sadly it's very easy for strict type
returns to override that result so in
this case
and get user strict we have a return
type of user which only has a username
and an email so even though we are
returning something with a password that
we would want to see in our types
definition it's not there anymore by
putting this type here we have
overridden the type of this or we've
overridden the type such that password
magically vanishes in typescript land
even though it's still there that's a
lie this is an incorrect type definition
if we take a look at the diagram for
this it should highlight where the lies
are happening so we again have our black
circle and the truth within it the type
of user.password when we call user is
very different depending on which of
these Solutions we use to type it the
truth of what user.password is here is
pass because that is what we're getting
back when we call user.password if we
use raw inference we're going to get
back a string which is fine it lets us
know that we have a string there when we
don't intend to and that the return or
the response of get user has a password
in it so it's still correct it just has
more vague around what the type is
because it's a generic string not the
specific string totally fine
the return type will actually give you
an error here when you try to touch
check or interface with user.password it
will error because you've told
typescript no that doesn't exist even
though it does the return type is now
giving you an error on data that
actually exists and you have all of the
things to know that that data exists
if you ask constant you're going to get
passed because that's what the value is
here and it's now been made into a
constant but the harsh reality here is
that all of these are the truth except
for return types
because return types here
contain some of the truth but are also
missing some of it
they're lying a lie is when you don't
include the truth in your response and
that is what I see here when you use
return types it becomes much easier to
lie and that's a huge concern to me
we can negotiate and argue all day
around the merits of making your type
definition closer to the truth but we
also have to acknowledge that return
types allow you to move the type further
away from the truth and outside of the
scope of Truth very scary for my final
example I want to show the code that
primogen gave an example with on stream
yesterday because although it looks good
on the stream we later figured out it's
entirely broken and super risky so much
so that Prime even replied earlier today
saying I showed overloading lying which
it does and typescript should get rid of
that behavior immediately well
typescript behaves how typescript
behaves and right now return types
enable typescript to lie a lot in this
example we have a type user which has a
role either user or admin we call this
get user function I need to get user
overrides because this is the one we're
overriding it you call it an ID we call
it with a role we then return that role
ideally we'd probably return other
things here like permissions and stuff
but the example is meant to be simple
where roles user we get back roll user
role as admin we get back roll admin the
override here is basically telling
typescript oh by the way if you pass
this you're guaranteed this subset of
the type because get user overrides
always returns a user and both of these
are valid users so we've effectively
said here is if the input matches this
type then the response has to match this
type
I don't know how closely you've been
looking but that's not the truth here
because if roll is user we're not
returning role user we're actually
returning role admin if you didn't
notice that then you would have failed
this encode review because guess what
the types are lying here if we look at
user override the response will get user
override with user it thinks the type of
is role user but it isn't we have just
used the override here to lie to
typescript because we told typescript no
you don't know better about our types we
know better about our types but we don't
here we were wrong and a code reviews
the only way you're not going to ship
this code
however
if you just let inference do its thing
you're going to get a more vague type
sure it's not ideal I understand but in
this case this more vague type of string
or null is the truth and I personally
believe truthy code is more valuable
than slightly more narrow type
definitions if we take a look on the
diagram here you'll see why this one's
so scary the truth is roll admin and
sadly even with the consts we can't
narrow it down to here without the
possibility of lying the raw inference
would be roll string or null just pretty
accurate totally fine to operate within
the override return type so if you're
using overrides for the return type on
this it's now going to be roll colon
user which is a lie if we ask cost
everything we're gonna get back roll
user or roll admin or null because it
knows strictly what these are that
doesn't necessarily know the mapping of
when you pass a specific role which
thing comes back that all said God
override return types just don't exist
within the truth at all in this case
you'd have to actually modify the code
to bring these back to the truth and
then all future code modifications have
to be cognizant of the fact that this
type may not overlap with the truth and
you as a developer have to be very very
proactive to make sure that happens
or way easier just don't give it a type
the vast majority of the time if you
don't type the response of the function
the type you get back is good enough to
work with and on the rare occasions it
isn't you can as constant move on you
really want this function of a specific
narrowed down type you better put a
massive comment on it letting future
developers know that it's easy to lie if
they aren't careful once we get into any
this becomes way more common but even in
these simple use cases where all of the
inputs and outputs are strictly typed
return types often lie to you
so be careful don't use return types if
you don't have to I don't think they're
100 evil I think they're closer to like
20 I just wish we would acknowledge that
20 evil and be very very careful about
how we introduce evil into our code
bases inference always tells the truth
even if the truth is more vague return
types can lie to you and you should be
careful when you use them as good as I
am a typescript I relied on much smarter
people to help build this stance and
also find all of these examples so I'm
going to let all of them let you know
what they think
hey I'm Malta and I prefer inferred
return types I'm trash and I generally
prefer inferring my return types hey I'm
Ben and for strong intuitive safe typing
I try to default to inference in
typescript hi my name is Josh Goldberg
and I generally prefer inferring return
types hey I'm Dax and I prefer inferring
return types hi I'm Maple Leaf and I
prefer inferring return types hey I'm
Alex and I almost always in fire types
hi there I'm Tanner lensley and a vast
majority of the time I use inferred
return types
hi I'm Ken C Dons and although I don't
like hard and fast rules most of the
time I infer my return types hi I'm Napo
cook I think you should be using
inferred return types by default except
when you have a function with multiple
branches except in library code and
except when you have really Niche weird
performance concerns with the typescript
compiler where a return type solves it
but that's it by default use implicit
returns hopefully we can end this
conversation once and for all if you
want to know more about ways people use
typescript wrong I'm going to pin a
video right there so take a watch of
that one should be good
peace nerds
Browse More Related Video
5.0 / 5 (0 votes)