An introduction to type programming in TypeScript
zhenghao.io
zhenghao.io
It's too bad Flow has lost the typed-JS battle, I find the syntax to be a lot easier to use.
[0] https://www.youtube.com/playlist?list=PLw5h0DiJ-9PBIgIyd2ZA1...
Unfortunately, having all that power available is necessary because it has to be able to reasonably describe a highly-dynamic language. The more dynamic your JS is to begin with, the crazier your types will have to be to make sense of it. But most of that craziness can be avoided if you write straightforward logic with straightforward data structures to begin with.
I've had to break out some wild types to describe JS modules I've needed. If I need such things inside a TS application I control, I often see that as a failure to write clean/concise code in the domain language of the application itself rather than some "ideal" abstraction that may not matter (and I expect will eventually crumble into unreadable tech debt).
Or crumble when tsc tries to follow them ;)
I’ve sometimes found, perhaps for the better, that when I get too creative with types the typescript compiler will at some point just not be able to follow what I’m trying to tell it any more. Even though my types are correct, theoretically, it will just sort of tip over. That usually serves as a good sign that I shouldn’t be trying to do what I’m doing at all.
Well, good news, you can use Typescript's compiler as a Js static code analyzer without writing a single line of Typescript!
It is OK if you prefer no solution to some complex typing needs that are solved with complex syntax in Typescript.
Most of Typescript is optional.
It's not trivial to think of simpler alternatives to much of the problems Typescript is tackling.
(And if you have any simplifying syntax suggestions that don't break typing it will be interesting to read)
Yeah, is it. But "complexity" is fine:
Complex is better than complicated.
- [Zend of python](https://www.python.org/dev/peps/pep-0020/)
What is a big trouble is when the complexity is NOT intentionally designed (ie: in languages like oCalm, Rust, Coq...) but instead the type system is a lie that bring "complications": //A bad language, like JS, with both complexity AND complications:
[] - {}; // NaN
Humans can deal with complexity if is part of a intentional design (example: APL), but what we dread is when is accidental... [] - {}
is a fatal typescript error[0]. A well configured linter can also catch out similar nonsense, but
[] - 2
does get past the compiler.The TS Compiler can atleast stop you from doing nonsense like applying operators to types where they don't make sense. Of course, it'd be better if JS just threw an error or something, but atleast TS can stop you.
[0]: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.ts(2363)
Or did you mean to say that oCaml, Rust, and Coq have intentional design complexity?
yes, more like this (in special Rust, that deal with many challenges like system programming, safety, etc).
[1] https://www.reddit.com/r/JSdev/comments/nl4ccq/is_flow_movin...
Most of this is just the way the language evolved, along JavaScript. I wish they'd abandon the "JavaScript superset idea" and cleaned up the language.
Make the common case simpler and more straightforward, drop everything exotic, it's not practical nor strictly necessary.
After writing TypeScript for a while, it occurred to me that the TypeScript language actually consists of two sub-languages - one is JavaScript, and the other is the type language.
For the JavaScript language, the world is made of JavaScript values; for the type language, the world is made of types.https://hirrolot.github.io/posts/why-static-languages-suffer...
In TypeScript or JavaScript? Can you say more?
Type variables abstract over types and are analogous to function parameters at the values level. Think the ‘T’ in ‘List<T>’.
If I want to use process.env.NODE_ENV I first have to create a new environment.d.ts, declare the interfaxe and export an empty object just so the typescript compiler is satisfied. It sometimes just adds too much boilerplate.
What you are doing when you create the environment.d.ts file is forcing the transpiler to assume the variable will have been set, which is not really true. The program may still end up being executed in an environment in which the variable was not set.
Instead, what I like to do is create a config file in your project where you export an object containing all configuration values for your project. There, you can set default values for variables coming from the environment. In this way, you guarantee a value will be present for the execution of your program:
export const config = {
dbConnectionString: process.env.DB_CONNECTION || 'localhost:27017',
nodeEnv: process.env.NODE_ENV || 'development',
}
Remember that the NodeJS runtime guarantees the setting of no environment variables. The NODE_ENV variable is simply a convention that was started by express.https://www.typescriptlang.org/docs/handbook/release-notes/t...
You're right that the runtime itself doesn't guarantee any env vars. I'm not sure who used it first, but npm also sets NODE_ENV (and some other env vars I think) in its different lifecycles, depending on if you provide the --production/--no-production flag when running it. But not sure if that came after or before express started using it.
// v is any or unknown
if (typeof v !== "string") {
throw new Error("oops")
}
// v is now string
You can’t get runtime type correctness by deceiving typescript into it.https://www.npmjs.com/package/@types/node
(ETA: It's mentioned in the StackOverflow and they still add an extra definition on top of it, but the env in the types today is a Record and you don't have to do it, you just won't get auto-completion on the names.)
And here a type-level RegExp matcher: https://github.com/EvolveYourMind/ts-regexp
This would have been much easier if I'd had ts-regexp at the time :)
https://kdy1.dev/posts/2022/1/tsc-go
Ok yup, definitely that one, https://news.ycombinator.com/item?id=30074414
edit: I am used to working with Java in Eclipse where the type warnings make much more sense
I find the examples that followed to be a demonstration without purpose.
After reading them I don't know when to use them, he mentions "type gymnastics" at the end and I find that most of the examples are demonstrations of type gymnastics.
I work on a large Typescript codebase and rarely I need to do abstract typing in order to get something done, Typescript can be used in a very direct and objetive manner and it's usually the route I prefer.
GitHub issue about the Turing completeness:
https://github.com/microsoft/TypeScript/issues/14833
Proof of Turing completeness:
https://gist.github.com/hediet/63f4844acf5ac330804801084f87a...
Using Tiobe's top 20: I'd guess Swift, Delphi, Fortran and Go
C++, Java, Rust, Haskell, Typescript have a Turing complete type system. C#: don't know, could be.
https://forums.swift.org/t/swift-type-checking-is-undecidabl...
type IsPrime<
MaybePrime extends number,
NumAsTuple extends unknown[] = [],
RemainderAsTuple extends unknown[] = NumAsTuple,
> =
MaybePrime extends NumAsTuple["length"]
? NumAsTuple["length"] extends RemainderAsTuple["length"]
? NumAsTuple["length"] extends (1 | 2 | 3 | 4 | 5 | 6)
? NumAsTuple["length"] extends (1 | 2 | 3 | 5)
? true
: false
: NumAsTuple extends [infer _, infer _, infer _, infer _, infer _, infer _, ...infer Rest]
? IsPrime<MaybePrime, NumAsTuple, Rest>
: false
: RemainderAsTuple["length"] extends (1 | 2 | 3 | 4 | 5 | 6)
? RemainderAsTuple["length"] extends (1 | 5)
? true
: false
: RemainderAsTuple extends [infer _, infer _, infer _, infer _, infer _, infer _, ...infer Rest]
? IsPrime<MaybePrime, NumAsTuple, Rest>
: false
: IsPrime<MaybePrime, [...NumAsTuple, 1]>;[1]: https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgzgBQE4...