If you're too impatient to wait for first-class optional chaining in TS, there's a nice open-source library for it that's been around for a little while:
The "Assert signatures" feature looks excellent. The biggest issue with typescript has always been validating external inputs actually meet the type contracts that your code says they do. With this, it looks like this could be written as library!
How do you verify it now? I've been using typeguards, but since i haven't found a good way to generate interfaces from typeguard functions or typeguard functions from interfaces I have to do each manually:
You can validate objects with `ContactInfo.decode(someObject)`
Note that we can have the same name for the type and value because they live in different namespaces. When you do ContactInfo.decode, you're calling the decode property of `const ContactInfo`. When you use `ContactInfo` in a type position (e.g. `function x(arg: ContactInfo)`), you're using the `type ContactInfo` declaration
- typescript-is[2]
This uses TypeScript's transformer API. You can use it with https://github.com/cevek/ttypescript. It generates validators for your interfaces/types/etc at compile-time.
I've been hesitant to switch to something that demands custom type declarations, because we're already autogenerating a lot of types/interfaces with express-openapi (we lean heavily on their request and response validators, too but those don't cover all the types we make), and getting that to play nicely with custom declarations is not my idea of fun. But for the types that aren't tied back to an json-endpoint (we have a few endpoints where we're getting xml or csv or xlsx and a few db<-->backend only interfaces), this looks like a great solution.
Typescript-is looks like it might have an overall edge, though, because we can use it on the autogenerated types as well with almost no hassle.
In addition to the suggestions in the sibling comments, I've had good luck with ts-interface-checker/ts-interface-builder . You add a code generation step to your build process (rather than ttsc) that generates runtime equivalents of your TS types, and there's a library to perform a runtime check.
Definitely. Using Flow, type refinement has been one of my biggest annoyances, because the list of things the type system recognizes as such is hardcoded and can't be extended:
instanceof
typeof
Array.isArray()
== null
And if you want to refine object types it gets even worse; you have to just check for properties that may or may not be there, which means those properties have to be rigidly distinguishable between object types in a union, etc. etc. Being able to do custom, rich object validation and give it first-class hooks into the type system sounds incredible.
1. Use discriminated union types: https://www.typescriptlang.org/docs/handbook/advanced-types.... - TypeScript these days sticks with the runtime semantics of JavaScript, and discriminated unions are a very natural way to express algebraic data types in JS.
There are a few ways to get exhaustiveness checking in TypeScript when using tagged unions. The way I usually do it is an assertNever function like this:
function assertNever(value: never): any {
return value;
}
Then if you call assertNever on your variable in the default switch case or the last else block, TypeScript will error if you didn't handle every case, since it expects the variable to have been narrowed to the "never" type since there's no remaining value that it can take on. That's also a good place to do a runtime check since TS types aren't guaranteed to match runtime values.
TypeScript isn't really a new language. It's a (mostly) type-checking-only extension to JavaScript. The team has made a policy of not adding any more runtime behavior changing features. JavaScript will need to add pattern matching for TypeScript to get it.
Oh I know, I actually don't expect it from Typescript. It's portability with JS code is TS's best feature and I don't see how you could marry the two (maybe I'm wrong here). I just wanted to share how much I like pattern matching.
The biggest advantages of io-ts over the jsonschema based type generation approach is that our data doesn't have to be json and we can handle non-serializable and complex data structures eg. class instances etc.
This makes it additionally useful for scenarios where we are writing a typescript library but also want good descriptive error messages for users who use vanilla javascript.
Even for type-checking at io boundaries [1], it is more useful than jsonschema because using io-ts we can, besides validating the data, also transform our incoming and outgoing data into richer data-structures (eg. string <-> date instance, plain javascript objects <-> class instances) through use of encoders and decoders.
it feels like the new features for recent languages are starting to look the same because they're nice. Kotlin has this stuff too. Rust and Kotlin have a similar style of null handling.
Point well made. I've spent some time with TS, Rust, and Kotlin recently and I really enjoy how they all have these kinds of features. Really feels like they see how well it works elsewhere and learn from one another.
Yeah I was going to say the same thing - love that optional chaining syntax... Would cut down so many checks and balances needed to avoid those errors.
Availability of recursive-types is a great news for users of libraries like Mobx state tree [1] which heavily lean on inferred & derived types.
Circular type references among MST models have so far required quite a bit of ceremony [2] to deal with. Really looking forward to get rid of that boilerplate.
I am really hoping for private properties and compiler support of class properties (it supports the syntax, I think, but doesn't compile them down from what I understand).
Nice to see optional chaining. It was the one feature I missed the most from CoffeeScript. The null coalescing is also nice - I’ve been bitten more than once with falsy values reverting to defaults on assignment.
top level await doesn't make async operations synchronous.
It mostly eliminates the need to have immediately evaluated wrapper async functions that we would have needed so far.
(async () => {
await foo();
})();
The added benefit is that imported scripts would be implicitly awaited upon, which has been clunky to do otherwise - you'd need to have a module that exposes an async function and expect the consumer to await on them. But the moment you do that you'd no longer be able to directly run the script through node, so you'd end up needing one more file that imports this module and runs it directly.
Availability of top-level await makes experimenting with (promise-returning) APIs in REPL much easier. It is also a bit step forward in making typescript more useful as a general purpose scripting language (outside webdev context).
> top level await doesn't make async operations synchronous
No, it just lets us write them like they look in synchronous languages.
So we're jumping through even more hoops to avoid the realities of asynchronous JS. IMO it's better for the asynchrony to be explicit. A whole generation of frontend devs aren't going to have any idea how their code is actually running.
Does anyone know when TypeScript plans to introduce dynamic typing for function/method parameters? It would be very useful if TypeScript could infer the type of variables at runtime so that you never have to specify it.
I may have missed your point, but wouldn’t this be essentially useless? You then have no type information about the parameters at all. Wouldn’t this just be the same as the existing implicit “any” type when not in strict mode?
Strongly typed functional languages (including Reason) can often figure out a function's parameter types based on how the variables are used in the function. For example, given `(a, b) => a.push(b * 2)`, it could figure out that `b` must be of type `number` and `a` must be of type `Array<number>`, so the function author wouldn't need to write the type annotations.
I think it's likely that TypeScript will never implement this (at least not at the level of sophistication of typical functional languages), given that it adds a lot of complexity to the language, and making types explicit at boundaries is usually good practice anyway.
It's arguable that they might, actually, add this in the future, but ... it would probably show up as part of how you can use TypeScript to type-check your JavaScript code such as when it infers types from JSDoc.
Repo: https://github.com/rimeto/ts-optchain
Blog post with some details: https://medium.com/inside-rimeto/optional-chaining-in-typesc...
(I don't work for Rimeto, but a close friend did, which is how I stumbled on that blog post.)