DEV Community

Cover image for Typescript: It's not actually validating your types.

Typescript: It's not actually validating your types.

Red Ochsenbein (he/him) on August 11, 2022

Typescript is a nice thing: It lets you define types and make sure your classes and functions adhere to certain expectations. It forces you to thin...
Collapse
 
joelbonetr profile image
JoelBonetR 🥇

Nice one!

I use Joi for this kind of validations, I may take a try to Zod to see the differences and which one is more convenient depending on the use-case.

Thank you for sharing! 😁

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him) • Edited

Joi can do a lot more than Zod (like dealing with linked references, etc.) and is much closer to JSON schemas, this might be a great thing to have for really complex cases. But I'd say Zod being simpler makes it more suitable for many smaller to midsize projects which don't have to deal with that much complexity. (Oh, and Joi is quite a few years older than Zod)

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him) • Edited

Thanks for commenting and suggesting io-ts. Just looked into it. I see how it works, but in contrast to zod it feels a bit "academic" which might put off some people.

Collapse
 
qm3ster profile image
Mihail Malo

but what if "academic = good, some people = bad"

Thread Thread
 
syeo66 profile image
Red Ochsenbein (he/him)

Well, I think this is an excluding opinion. But sure, if you have the time and resources to teach everyone in your team... more power to you.

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him) • Edited

Hm, works only on classes. This makes it rather limiting (especially for people tending towards a more functional style.)

(Update: Just realized there is also a way to work without those decorators and validate plain objects. But it feels rather cumbersome. I think I prefer the Zod way, and for more complex stuff I'd probably use Joi)

Collapse
 
elsyng profile image
Ellis

To my knowledge & experience, type safety is typically (much) less important in a frontend app than in a backend app.

Meaning: we don't need to obsess about it, or spend effort into it, nearly as much. Relatively speaking. A lot of the static or run-time type checking might be unjustified and overkill.

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him) • Edited

And then clients wonder why they only see a white screen...

Seriously, yeah, browsers are usually quite forgiving. Which can be a blessing and a curse. For the "curse" side we do have those tools which help us make things more deterministic and make us really think. This helps a lot in creating robust applications with proper error handling by making us aware of some possible edge cases. But you are right, the backend side should (!) be way more rigorous all the time. Unfortunately I saw way to many instances of neglect in the vain of "let's fix that in the frontend"... which is not a good thing to do... but at least the frontend catches those things by being more pedantic than it has to be.

Oh and also... my article wasn't targeting the frontend or backend side specifically.

Collapse
 
paulwababu profile image
paulsaul621

I agree, TypeScript is not actually validating your types. It's simply checking that the types you've written down match the types of the variables you're using. If you assign a string to a variable that's meant to hold an integer, for example, TypeScript will give you a warning, but it won't stop you from running the code.

Collapse
 
boutell profile image
Tom Boutell

Good article on a common confusion about TypeScript. I must be missing something here:

const UserType = t.infer<User>
Enter fullscreen mode Exit fullscreen mode

Should "t" be "z" here or is it coming from somewhere else?

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him)

Oops. Typo. Yes sould be z

Collapse
 
zhouyg profile image
zhou-yg

nice point.It's really different between static compiler and dynamic runtime, lots developers confused with them sometimes

Collapse
 
thi3rry profile image
Thierry Poinot

Have you try objectmodel ? objectmodel.js.org/

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him)

No, never heard of it before. At first glance it seems to be quite interesting, but also trying to do a bit too much for my taste. But it certainly seems to be powerful.

Collapse
 
csaltos profile image
Carlos Saltos

This is one of many reasons why at my company we replaced the old TypeScript by the Elm language ... we have a lot of peace and joy coding now 👍😎

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him)

While elm is quite a nice language I would be worried using it in production. It being stale since 2019 and being mostly 'maintained' by one person is quite a risk.
Having said that: You'd have the exact same problem in elm, too. Elm is not validating the types in the runtime. Sure the Maybe monad helps but under the hood it still does not make sure an expected string from an external source is not actually - let's say - a number.

Collapse
 
qm3ster profile image
Mihail Malo • Edited

Someone really likes their return statements, huh? :v

const justAFunction = (n: number): string => `${n}`
Enter fullscreen mode Exit fullscreen mode
const beans = {
  string: (x: string) => x,
  object: (x: string[]) => x.join(' ')
} as const;
const justAFunction = (str: string[] | string): string => beans[typeof str](str)
Enter fullscreen mode Exit fullscreen mode
// no need for `Promise` here, btw, the `async` keyword takes care of it. In fact, that would never be correct, as they get "unwrapped" recursively
const retrieveUser = async (): User => (await fetch('/user/me')).json()
Enter fullscreen mode Exit fullscreen mode

or

const retrieveUser = (): Promise<User> => fetch('/user/me').then(x => x.json())
Enter fullscreen mode Exit fullscreen mode
const validate = (obj: any): obj is User => obj !== null 
    && typeof obj === 'object'
    && 'firstname' in obj
    && 'lastname' in obj
    && 'birthday' in obj
    && typeof obj.firstname === 'string'
    && typeof obj.lastname === 'string'
    && typeof obj.birthday === 'string'
Enter fullscreen mode Exit fullscreen mode

or, a decent pattern instead of is guards:

const yeet = (err: string | Error) => {
  throw typeof err === string
    ? new Error(err)
    : err
}
const validate = (obj: any): User => obj !== null 
    && typeof obj === 'object'
    && 'firstname' in obj
    && 'lastname' in obj
    && 'birthday' in obj
    && typeof obj.firstname === 'string'
    && typeof obj.lastname === 'string'
    && typeof obj.birthday === 'string'
    && obj as User
    || yeet(`expected User, got ${obj} 🐴`)
Enter fullscreen mode Exit fullscreen mode

Nice Zod you got there tho, unironically

Collapse
 
syeo66 profile image
Red Ochsenbein (he/him) • Edited

I can write less verbose code. Easy. But especially when writing an article I tend to be rather be explicit and simple than short and clever. Especially when you think about the scope of an article...

All this to say: I'm usually quite intentional in how I write what.

Collapse
 
qm3ster profile image
Mihail Malo

Nothing about terseness, I just have statement-phobia.