5 ms·
[TypeScript] does not actually ensure that the data you are manipulating corresponds to the type that you have declared to represent it. For example, the data m
by lacker 6y ago
[TypeScript] does not actually ensure that the data you are manipulating corresponds to the type that you have declared to represent it. For example, the data might contain additional fields or even incorrect values for declared types.
This is only a problem if you are mixing untyped code with typed code, isn't it? Like when you are parsing JSON, you need to do typechecking right then, rather than just using an "any" type. The only other situation I have run into this in practice with TypeScript is when I'm using a library that has slightly misdefined types.
- lmm 6y ago> The only other situation I have run into this in practice with TypeScript is when I'm using a library that has slightly misdefined types. Unfortunately there's no way to know which libraries have defined their types correctly, so you end up having to check the types you get back from every library you use.
- nicolodavis 6y agoThat's correct. You have to insert validation code at all the entry points, which was the case for me. Moving to Rust doesn't eliminate validation altogether, but you don't have to do any type related validation which is nice.
- mcny 6y agoNot sure if this is a place to ask this but if someone does not have experience working with Javascript, they might have trouble reasoning about this code: https://codesandbox.io/s/is849 https://codesandbox.io/s/is849 edit: complete code ```typescript class Person { id: number; name: string; yearOfBirth: number; constructor(id: number, name: string, yearOfBirth: number) { this.id = id; this.name = name; if (yearOfBirth < 1900 || yearOfBirth > 2020) { throw new Error("I don't understand you. Go back to your time machine."); } else { this.yearOfBirth = yearOfBirth; } } getAge(): number { const currentDate: number = new Date().getUTCFullYear(); return currentDate - this.yearOfBirth; } } class Dog { id: number; name: string; yearOfBirth: number; constructor(id: number, name: string, yearOfBirth: number) { this.id = id; this.name = name; if (yearOfBirth < 1947 || yearOfBirth > 2020) { throw new Error("I don't understand you. Go back to your time machine."); } else { this.yearOfBirth = yearOfBirth; } } getAge(): number { const currentDate: number = new Date().getUTCFullYear(); return (currentDate - this.yearOfBirth) * 7; } } const buzz: Person = new Person(1, `Buzz`, 1987); const airbud: Dog = buzz; console.log(`Buzz is ${buzz.getAge()} years old.`); console.log(`Airbud is ${airbud.getAge()} years old in human years.`); ```
- dfee 6y agoWhat’s confusing? I must’ve missed it in my cursory scan.
- s-lambert 6y agoDog and Person are structurally the same so you can assign a person to a dog and vice versa. But that's just how structural typing works and as a user of TypeScript I haven't run into a case where this'd be an issue.
- dfee 6y agoHaha oh. Yeah, assumed that the Dog definition wasn’t worthless. Indeed TS is structurally typed. And that’s nice!
- cheerlessbog 6y agoI worked on a web based editor. A library would give us a range to highlight, in 1-based coordinates. The editor control was 0-based. As you can imagine it was easy to forget to translate back and forth in one path or another. In a strongly typed language I would simply define two Range types and the compiler would eliminate the mistake. I assumed Typescript could help me in the same way but it allowed the two types to be interchanged silently because they had the same structure. Perhaps I was holding it wrong?
- panzerklein 6y agoTypescript has two hacks that help with mixing of similar data and introduce somewhat-nominal typing - branding and flavoring [1]. Also see smart constructors [2] for more functional approach. [1] https://gist.github.com/dcolthorp/aa21cf87d847ae9942106435bf47565d https://gist.github.com/dcolthorp/aa21cf87d847ae9942106435bf... [2] https://dev.to/gcanti/functional-design-smart-constructors-14nb https://dev.to/gcanti/functional-design-smart-constructors-1...
- 6y ago
- tigershark 6y agoNo, nominal types are extremely useful to ensure the correctness of your software. You can define a function to receive a FirstName and LastName instead of passing strings so you cannot accidentally mix up the parameters for example. There are several techniques to approximate nominal typing in typescript (https://medium.com/better-programming/nominal-typescript-eee36e9432d2 https://medium.com/better-programming/nominal-typescript-eee... for example) and there is an open issue https://github.com/Microsoft/Typescript/issues/202 https://github.com/Microsoft/Typescript/issues/202 but it’s still not being considered for implementation as far as I remember.
- filleduchaos 6y ago> This is only a problem if you are mixing untyped code with typed code, isn't it? I find it a bit strange that people talk about this as "only a problem", as though it was some weird niche edge case and not an ever-present issue. The written-in-plain-JS ecosystem completely dwarfs the written-in-TypeScript one; unless you're doing something rather trivial you're quite likely to end up depending on a library that barely had the shape of its objects in mind during development, with typings (if they're even present) that were contributed by someone that's almost definitely not the actual library author. Of course, if you're competent enough you can correct typings and always remember to run runtime checks on data that doesn't come from you and so on. But it's too easy for a beginner to fall into traps like mishandling data that comes from a dependency (especially when it's buggy/ostensibly has typings) - in my opinion, there should be a first-party compiler/linter option to enforce checks on any `any`.
- lacker 6y agoYou don't have to depend on badly-written untyped third-party libraries, just because there are a lot of them out there. Many projects and companies will avoid doing so. This is especially reasonable if your comparison is switching to a language like Rust; there are probably fewer third-party libraries available in Rust overall than there are libraries with accurate TypeScript definitions available.
- filleduchaos 6y ago"Badly-written" is of course subjective, but as for untyped/loosely typed I think it's a bit difficult to claim that people are avoiding using them when (for example) the typings for an obviously popular library like Express are chock-full of `any` types[0]. Including several (like request bodies) that should instead be `unknown`. I'm sorry but it's rather naïve to expect a beginner to TypeScript, especially one that's coming from JS, to not trip up at all using typings like that and a compiler/language spec that implicitly casts things declared as `any`. 0. https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/express-serve-static-core/index.d.ts https://github.com/DefinitelyTyped/DefinitelyTyped/blob/mast...
- 6y ago
- hebrox 6y agoWhen getting external data, it always good to do a combination of casting and validating. There are a lot of good libraries to help you with this: https://github.com/moltar/typescript-runtime-type-benchmarks https://github.com/moltar/typescript-runtime-type-benchmarks
- benschulz 6y agoNo[1], TypeScript is unsound in many ways. Most of them are intentional trade-offs to catch as many bugs as possible while not being too restrictive/allowing most JavaScript code to be annotated. [1]: https://codesandbox.io/s/te0pn?file=/index.ts https://codesandbox.io/s/te0pn?file=/index.ts Edit: Apparently TypeScript playground links cannot be shared :( Edit2: Published on codesandbox.io, hopefully that works