7 ms·
I wonder about a Typescript with alternate design decisions. The type system is cool and you can do a lot of compile time metaprogramming. However, when there's
by dhruvrajvanshi 2y ago
I wonder about a Typescript with alternate design decisions.
The type system is cool and you can do a lot of compile time metaprogramming.
However, when there's a type error in computed types, it's a nightmare to visually parse
type { foo: ... , bar: ..., ... } can't be assigned to type { foo: ..., bar: ... }. type { foo: ... bar: ..., ... } is missing the following properties from { foo: ..., bar: ..., ... }
Apart from repeating roughly the same type 4 times (which is a UX issue that's fixable), debugging computed types requires having a typescript interpreter in your head.
I wonder if we had nominal runtime checked types, it could work better than the current design in terms of DX.
Basically, the : Type would always be a runtime checked assertion. Zod certainly fills that gap, but it would be nicer to have it baked in.
The type system would not be as powerful, but when I'm writing Kotlin, I really don't miss the advanced features of Typescript at all. I just define a data class structure and add @Serializable to generate conversions from/to JSON.
- rlp 2y agoThis is my exact experience. TypeScript seemed to hit a complexity sweet spot about 5 years ago, then they just kept adding more obscure stuff to the type system. I find that understanding TypeScript compiler errors can be almost as difficult as understanding C++ template errors at times.
- phplovesong 2y agoThis. Haxe is a more sane TS alternative in 2024.
- jadbox 2y agoIt's Haxe still been actively developed? I loved it back in the day. The blog hasn't had an update in years.
- phplovesong 2y agoIt is. And only getting better SLOWLY by each iteration. The thing i love about Haxe that once you use it, your installed version is not legacy in a month (unlike npm/typescipt ecosystem). Haxe is fully working, and does not need a lot of "new" features. More news about Haxe can be found here: https://haxe.io/ https://haxe.io/ (the old blog is not updated AFAIK)
- earslap 2y agoHaxe is amazing, has macros etc. A force multiplier if you are a solo developer for sure. But damn, you feel kinda alone if you are using it. Not everything is an npm install away which negates your velocity gains from using a saner language.
- phplovesong 2y agoI RARELY/NEVER have to build an app so fast that i just fart out whatever broken code as fast as my fingers can type. IF i get a project like this with a deadline of "yesterday" i politely just refuse. I will be wasting my personal time, and the clients time. And the result will be a broken mess that will eventually take more time to fix, than it would have if i in fact did it "correct" from the get go. That said Haxe has externs, enabling you to target JS/PHP and use the rich ecosystem both langauges have. The best part of externs is that IF i only use 4 things from given package, i statically KNOW i only use these 4 things, and can refactor more easily, or even build the thing i need myself.
- earslap 2y agoWhen I'm talking about velocity, I'm not talking about coding fast, but being able to write DRY, flexible yet easily maintainable code that can weather future requirements / refactorings easily. Personally, I'm also talking in the context of my own projects so nobody is breathing down my neck or pressuring me with time. I just want to write good code that is a joy to maintain for years to come.
- pier25 2y agoIronically Haxe was inspired by ActionScript 3 which was the basis for the EcmaScript 4 proposal which was abandoned back in 2008 or so.
- epolanski 2y agoHint, 9 times out of 10 you only need to read the last part of the error. Also, there are many ways to make types opaque (not show their entire verbose structure).
- wrs 2y agoTypeScript has a crazy powerful type system because it has to be able to describe any crazy behavior that was implemented in JavaScript. I mean, just take a look at @types/express-serve-static-core [0] or @types/lodash [1] to see the lengths TS will let you go. If you write in TS to start with, you can use a more sane subset. [0] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express-serve-static-core/index.d.ts https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast... [1] https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/lodash/common/common.d.ts https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast...
- dhruvrajvanshi 2y agoRight. I'm aware. My point was that even though the type system is powerful, somehow, I'm able to represent everything I need to in Kotlin's type system just fine and it feels a lot more type safe because it will throw a type error at runtime in the right place if I do a bad cast. Typescript `as Foo` will not do anything at runtime, and it will just keep on going, then throw a type error somewhere else later (possibly across an async boundary). You can, in theory use very strong lint rules (disallow `as` operator in favour of Zod, disallow postfix ! operator), but no actual codebase that I've worked on has these checks. Even the ones with the strictest checks enabled have gaps. Not to mention, there's intentional unsoundness in the type system, so even if you wanted, you couldn't really create a save subset of TS. Then there's the issue of reading the library types of some generic heavy code. When I "go to definition" in my fastify codebase, I see stuff like this RouteHandlerMethod<RawServer, RawRequest, RawReply, RouteGeneric, ContextConfig, SchemaCompiler, TypeProvider, Logger> Which expands to this export type RouteHandlerMethod< RawServer extends RawServerBase = RawServerDefault, RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>, RawReply extends RawReplyDefaultExpression<RawServer> = RawReplyDefaultExpression<RawServer>, RouteGeneric extends RouteGenericInterface = RouteGenericInterface, ContextConfig = ContextConfigDefault, SchemaCompiler extends FastifySchema = FastifySchema, TypeProvider extends FastifyTypeProvider = FastifyTypeProviderDefault, Logger extends FastifyBaseLogger = FastifyBaseLogger > = ( this: FastifyInstance<RawServer, RawRequest, RawReply, Logger, TypeProvider>, request: FastifyRequest<RouteGeneric, RawServer, RawRequest, SchemaCompiler, TypeProvider, ContextConfig, Logger>, reply: FastifyReply<RouteGeneric, RawServer, RawRequest, RawReply, ContextConfig, SchemaCompiler, TypeProvider> // This return type used to be a generic type argument. Due to TypeScript's inference of return types, this rendered returns unchecked. ) => ResolveFastifyReplyReturnType<TypeProvider, SchemaCompiler, RouteGeneric> Other languages somehow don't need types this complicated and they're still safer at runtime :shrug:
- spencerchubb 2y agoCouldn't this be improved by showing a diff between the mismatched types?
- dhruvrajvanshi 2y agoYes, I did mention that the UX of the type errors could be improved and probably should, but once you start getting into conditional types, and nested types (which may not be fully expanded when you see the error), it gets hairy.
- mhh__ 2y agoCan you do any compile time metaprogramming in typescript?
- mhio 2y agoNot really - https://github.com/Microsoft/TypeScript/issues/16607 https://github.com/Microsoft/TypeScript/issues/16607. ts-morph provides an easy way to use the TypeScript Compiler API to view and edit the AST before compile. Once you get your head around the API, which has good examples but isn't thoroughly documented on the web. https://github.com/dsherret/ts-morph https://github.com/dsherret/ts-morph
- phplovesong 2y agoNope. For thins you pick Haxe (https://haxe.org/ https://haxe.org/), it has an awesome macro system, and a state of the art compiler thats really, really fast.
- mhio 2y agoHow does haxe modify a typescript project pre or post compile?