Live data from Hacker News

TypeScript’s quirks: How inconsistencies make the language more complex

blog.asana.com

61–70 of 216 posts

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#61
post #26
post #9

Earlier quoted context omitted.

Programming TypeScript has a section on “Simulating Nominal Types” [1]. You define a type that’s impossible to create naturally, and provide a function that asserts something is of that type. type CompanyID = string & {readonly brand: unique symbol} type OrderID = string & {readonly brand: unique symbol} type UserID = string & {readonly brand: unique symbol} type ID = CompanyID | OrderID | UserID function CompanyID(i…

> TypeScript can be very confusing sometimes That's not good. A type system should be crystal clear, predictable and reliable. > and given the learning curve Types should not be a complex thing with a steep learning curve. If you know Assembler and C it's pretty clear what types are about. Added complexity to your codebase is what you should try to avoid at all times. We have a limited capacity of things we can think…

> That's not good. A type system should be crystal clear, predictable and reliable.

The purpose of TypeScript is to provide static types to JavaScript without just turning it into a compile target. TypeScript type system is only confusing because it's modeling real-life ultimately type-less JavaScript code. It's not it's own language with it's own rules -- it lives and dies as JavaScript.

> Types should not be a complex thing with a steep learning curve.

Types can be as simple or complex as needed. Assembler and C have very simple type systems with very few features and can only model very simple situations. Types in TS don't have to be complicated -- blame JavaScript programmers for their crazy designs.

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#62

I don’t agree with the article’s claim that discriminated unions are just a JS compat feature. Many APIs type JSON serialised entities using a string property and this feature makes it very easy to write interfaces and code to work with them.

Author here! Yeah I think you are right that discriminated unions are useful more broadly than just legacy JS code. That being said, I still think TypeScript's solution to handling them of using "type guards" where the type of a variable changes in different scopes is definitely designed to match common JS patterns at the cost of added complexity. Most other languages I know of only have a single type for a variable…

> Most other languages I know of only have a single type for a variable (and if you want to pattern match you must give each case a new variable name).

FWIW, Go also changes the variable's type in type-switch cases: https://tour.golang.org/methods/16

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#63
post #17
post #3

The first example doesn't bother me and I think it's a weak argument. TypeScript allows literals[1] as types[0] so it is trying to use the object as a type. The correct use of: printDog({ breed: "Airedale", age: 3 }) is to explicitly cast it: printDog({ breed: "Airedale", age: 3 } as Dog) [0] https://www.typescriptlang.org/play/index.html?ssl=1&ssc=1&p... [1] https://www.typescriptlang.org/docs/handbook/advanced-type…

Casting is as bad as using "any". You can make the compiler think anything you throw at it as that type and you can get bitten at runtime.

Nope. This is not how casting works in TypeScript. To get an unsafe cast you have to go via the ‘any’ or ‘unknown’ types.

e.g.

‘foo as unknown as Dog’

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#64
post #3

The first example doesn't bother me and I think it's a weak argument. TypeScript allows literals[1] as types[0] so it is trying to use the object as a type. The correct use of: printDog({ breed: "Airedale", age: 3 }) is to explicitly cast it: printDog({ breed: "Airedale", age: 3 } as Dog) [0] https://www.typescriptlang.org/play/index.html?ssl=1&ssc=1&p... [1] https://www.typescriptlang.org/docs/handbook/advanced-type…

Casting can hide errors. It's better to assign it to a variable first that has a type declaration. const dog: Dog = { breed: "Airedale", age: 3 } printDog(dog) An IIFE is safe too: printDog(((): Dog => ({ breed: "Airedale", age: 3 })())

Actually this cast is safe in TypeScript, additional variables are unnecessary.

The statement ‘const d: Dog’ and the expression ‘d as Dog’ are equivalent w.r.t. type safety. The compiler will error in both cases the if the value is not a Dog.

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#65

I don’t agree with the article’s claim that discriminated unions are just a JS compat feature. Many APIs type JSON serialised entities using a string property and this feature makes it very easy to write interfaces and code to work with them.

Author here! Yeah I think you are right that discriminated unions are useful more broadly than just legacy JS code. That being said, I still think TypeScript's solution to handling them of using "type guards" where the type of a variable changes in different scopes is definitely designed to match common JS patterns at the cost of added complexity. Most other languages I know of only have a single type for a variable…

To add to what others have said: Kotlin is a language that does path sensitive (re-)typing of variables. This is often very convenient in the presence of OO-style polymorphism or in cases where the language supports ad-hoc unions.

Personally it doesn't feel complicated to use/understand (at least the kind of thing that these languages do)

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#66
post #51
post #24

Ok since we have a lot of TS people here maybe someone can help me out. Let's say I have a simple interface with a few fields. I want to make sure incoming JSON conforms to that interface. I realize at runtime the interface isn't there, but is there some tool I can use to compile a utility to check JSON against an interface without having to write a duplicative JSONSchema or something else?

I’d suggest generating code Write your interface in json or text proto then build it to ts interfaces and runtime checks.

Agree with the code generation approach. Otherwise you need to make sure the annotations are in sync with the type / class / interface.

Typescript doesn't support macro currently, so code generation is the only way to programmatically create 'type-checked' code.

Some cli-tool and library I'm using (available on npm):

tsc-macro: https://github.com/beenotung/tsc-macro

gen-ts-type: https://github.com/beenotung/gen-ts-type

ts-type-check: https://github.com/beenotung/ts-type-check

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#67
The following is purely anecdotally, my opinions is solely based on my personal experience with the language.

As someone who learned TypeScript just by using it and without any serious "study", I'll have to disagree the basic premise of the article.

I already knew about almost everything the article mentioned and nothing really seemed weird to me at the time.

The only point that I did not know about is type narrowing not working on nested objects, because that came up exactly 0 times in about 50k lines of TypeScript so far.

Half of the points made are actually TypeScript being lenient (interfaces allowing excess properties, classes working like interfaces). In my book this makes the TS easier to work with, because it gets out of the way when it's not needed.

Classes essentially working like interfaces is probably a result of TS wanting to be backward compatible with JS, because when you enrich your existing JS lib with type information, TS can't know about your "classes" - they're a runtime thing. Treating them the same as interfaces can make this much nicer.

It also allows 3rd party code to add extra properties to your new-instanciated object and using an interface to reflect the change, but still being able to pass it to stuff expecting the original thing. This way you can have type safety without losing JS features.

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#68

I don’t agree with the article’s claim that discriminated unions are just a JS compat feature. Many APIs type JSON serialised entities using a string property and this feature makes it very easy to write interfaces and code to work with them.

This. My network code uses them everywhere on the client side. It's frankly amazing.

Your server side code should have runtime validation though. You can't and shouldn't rely on TypeScript there for security reasons.

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#69
post #27
post #20

I still don't understand what pulls developers to Typescript. The examples given show major flaws in this (duck)type system. That it works when you don't use the 'any' type and when you know how to avoid all the edge cases and workarounds, I know. But when I see an example like this: const shasta = new Cat("Maine Coon") printDog(shasta) > Dog:Maine Coon I see a huge red flag. Coming from C/C++ it looks like a joke. W…

I've never used Typescript, but I don't think these are really 'major' flaws. That's just my perspective as someone that's being doing FE for over a decade and picks this stuff up fairly quick. Obviously it's more of a problem for newbs that probably aren't going to read that paragraph about discriminated unions and grok it straight away. Having said that, I absolutely hate the ending of this blog post. I see blog wr…

Try working with a large 5 year old JS codebase that's been hammered on by dozens of devs. The problems are no longer just pin point bugs but a systemic lack of modeling.

Static typing is not that much about preventing bugs but more about forcing the code to operate over a well defined model.

Can you write good code without static typing? Yes. Can you scale and maintain it in a large organization, probably not.

Re: TypeScript’s quirks: How inconsistencies make the language more complex

#70

The following is purely anecdotally, my opinions is solely based on my personal experience with the language. As someone who learned TypeScript just by using it and without any serious "study", I'll have to disagree the basic premise of the article. I already knew about almost everything the article mentioned and nothing really seemed weird to me at the time. The only point that I did not know about is type narrowing…

> TS can't know about your "classes" - they're a runtime thing. Treating them the same as interfaces can make this much nicer.

No–this is a very surprising and unsound choice and not at all what you would expect if you previously saw that TypeScript lifts classes into types.

> This way you can have type safety without losing JS features.

IMHO, you can't get type safety out of an unsound type system. (Which TypeScript is, by choice.) I think surprises like the above drive that point home.

Post reply on HN