import { ValidWords } from "./spellcheck";
// Typechecks cleanly:
const result: ValidWords<"the quick brown fox."> = "valid";
// Throws a type error
const result: ValidWords<"the qxick brown fox."> = "valid";
[0] https://github.com/kkuchta/TSpell1: https://github.com/kkuchta/css-only-chat 2: https://github.com/kkuchta/tabdb
I use this VSCode extension
https://marketplace.visualstudio.com/items?itemName=streetsi...
To spell check my code. It's surprisingly useful. It doesn't check at compile time but it does check camelCase and snake_case and even in typescript code I've found it highlight various actual issues.
export type ValidWords<T extends string> = T extends ""
? "valid"
: T extends `the${infer Rest}` | `of${infer Rest}` | `and${infer Rest}` | ...If you are looking for more practical and less academic languages, then Scala would be one of the languages that technically has a more powerful/generalized typesystem but at the same time is harder to use compared to Typescript's and cannot do some things that Typescript can do.
> In type-driven development, types are tools for constructing programs. We treat the type as the plan for a program, and use the compiler and type checker as our assistant, guiding us to a complete program that satisfies the type. The more expressive the type is that we give up front, the more confidence we can have that the resulting program will be correct.
Great stuff.
I think an example is how typescript can know, based on the first argument to a listener, what the Event type coming in will be
elem.addEventListner('mousedown', (foo) => {...});
elem.addEventListner('keydown', (bar) => {...});
typescript knows foo is a MouseEvent and bar is a KeyboardEventOf course you could argue that `addEventListener` is just bad design but I feel like there are legit uses to being able to associate an enum or string with type and I haven't seen that feature in other languages I've used.
This isn't because of the shortcomings of JavaScript, it's because of the shortcomings of simple type systems.
Simple type systems (like those of Java or Go) restrict the kinds of programs you can easily write while satisfying the type checker. Normally, the alternative is resorting to languages without static type checkers, like JavaScript.
TypeScript allows mostly idiomatic JavaScript even with complex runtime invariants to be given quite accurate types at compile time. It has features I miss all the time in Java.
Also, as you start getting complicated logic in your types, you need to test your types; make sure they admit things they should admit and reject things that they should reject. Ideally these tests can also serve some role as examples for your documentation.
Generally, these can just be some TS files that get compiled with `tsc`, but it helps to have a bunch of type-level assertions about expected types.
I actually recently gave a talk on "Lessons Learned Maintaining TS Libraries" [3], and had a couple slides covering the value of type tests and some techniques.
[0] Redux Toolkit's `createSlice`: https://github.com/reduxjs/redux-toolkit/blob/9e24958e6146cd...
[1] Reselect's `createSelector`: https://github.com/reduxjs/reselect/blob/f53eb41d76da0ea5897...
[2] React-Redux's `connect`: https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3...
[3] https://blog.isquaredsoftware.com/2022/05/presentations-ts-l...
I’m writing a HTTP client based on composition. The exact details aren’t important, but one of the goals is to have a strong type system for describing a valid pipeline of things like response parsers. Imagine something like
Doing “type tests” alone isn’t too hard - we can just use conditional types and the extends keyword. If the code compiles, fine.
But the harder part is negative type tests. “Given this code, the developer should get this error from TSC”. But this is just as important a part of the API; your types are there to convince the consumer that they can call a type-checked API with confidence.
In theory it should be plausible to run TSC programmatically. The issue is that TypeScript’s ScriptProcessor API really wants to be called with files on the filesystem rather than source text. So I am having to do some bodging. If I can get something sorted I may write a repo to demo it, I think it is a common problem.
I really wish people would focus more on keeping types as simple as possible instead of using that complexity just because the language allowed it.
Typescript is just one of those languages where things can get carried away but then reigned in again with a nice complexity gradient.
sorry about that
https://github.com/cypress-io/cypress/blob/develop/cli/types...
[0]: https://github.com/JoshuaKGoldberg/eslint-plugin-expect-type
TypeScript's type annotations are really a DSL embedded into JavaScript. And they can, and, depending on the problem at hand, should be treated as such.
I think this is the key. If treated as you describe, meaning the advanced types are well-written, well-documented, and well unit-tested as if they are "true" code, then using them shouldn't be too much of an issue.
However, I think people often just assume that the types aren't "real" code and thus the normal concepts of good software engineering don't apply and type monstrosities which nobody can understand result.
Imagine if this code[0] wasn't well-documented, fairly clearly written, and also tested. It would definitely be a liability in a codebase.
In addition, the rules of how advanced TypeScript concepts work can be quite nuanced and not always extremely well defined, so you can end up in situations where nobody even _really_ understands why some crazy type works.
[0]: https://github.com/sindresorhus/type-fest/blob/2f418dbbb6182...
So yeah, using discriminated unions, branded types, mapped types etc. in moderation can substantially reduce the surface area of errors - more so than other mainstream nominally typed languages. However, trying to model and prevent every invalid state at type level can lead to a serious drain in productivity. And, I am not really sure how to draw a line between.
I've seen many projects where the typing is done so well that it can infer and include all the data I've fed into the TS-defined functions / classes, which is great for IDE autocompletion.
(I'm a bit sleepy, so this is the main one I can think of at the moment that I really enjoy using.)
Turing completeness means for TS that for every computable function, there is a TS type that can compute that function (if TS wouldn't limit the recursion depth).
When this happens, typescript language integration (like in vs code or sublime text) will suddenly fall over and stop working correctly, and it'll be near impossible to figure that out too.
Our build uses rollup to invoke tsc and as it happens their profiling system doesn't actually measure how long tsc takes to run - the time is unaccounted :) So in general, be aware that 'typescript is taking a long time to compile' is a blind spot for this whole ecosystem and if you hit it you're going to have to work hard to fix it.
https://docs.microsoft.com/en-us/archive/blogs/ericlippert/l...
- RegExp matching through types: https://github.com/desi-ivanov/ts-regexp
- Lambda calculus through types: https://github.com/desi-ivanov/ts-lambda-calc
- Brainfuck through types: https://github.com/susisu/typefuck
There are lots of Lisp DSLs using macros which have been maintained by different people over several decades.
I also wonder if you could compile TypeScript to TypeScript types? After all, you want your type manipulation code to be typesafe.
Example of the code: https://github.com/pj/typeshaman/blob/main/packages/graphql/...
Documentation is incomplete, unfortunately I had to get a job. I started working on encoding all of SQL as well.
Wordle: https://codesandbox.io/s/wordle-typescript-d4srgi?file=/src/...
Anadrome(Anagram Palindrome): https://codesandbox.io/s/anagram-palindrome-7u14xr?file=/src...
Candy Crush 1D: https://codesandbox.io/s/candycrush-u2v5pr?file=/src/index.t...
[0]: https://effectivetypescript.com/2022/02/25/gentips-4-display...