16 ms·
TypeScript 3.7
- mceachen 7y agoThe preview release announcement for this version made FP on HN already, but it's a biggie: * Optional Chaining & Coalescing * Assertion Functions * .d.ts Emit From .js Files * Smarter Control Flow Analysis * Flatter Error Messages also great: * Function Truthy Checks / Uncalled Function Checks (which was tslint's biggest value prop for me up until now)
- vosper 7y agoWhat's the end state for TypeScript? Does it one day become feature complete and slow down? One of the frustrating things about trying to find help with TS today as a beginner is the plethora of SO and blog posts talking about much older versions. If you're lucky there'll be some comment "As of 2.6 you can now do ...", but even 2.6 is a lot of versions back - how do I know that's still the best way to do it in 3.7? I'm for progress, but it makes me a little wary to start my team of no-previous-TS-experience JS devs on a TypeScript project when there's still a new version every few months. Keeping up with Webpack is enough of a hassle...
- bobbytherobot 7y agoHow do you handle other language - including JavaScript - updates for your team?
- vosper 7y agoJavascript doesn't change at anything like the pace that TypeScript does, so it hasn't been much of a hassle. But even so we (like many teams with large codebases, I suspect) have callbacks, promises, and async/await all mixed together, depending on when the code was (re)written. It's on our list.
- wwwigham 7y agoJavascript formally releases once a year, but individual feature adoption in browsers is totally separate from that, and happens.... whenever they feel like it. v8 (chrome's js engine) doesn't have a set release schedule, but has already had 6 formal minor releases this year, each partially adopting some new JS runtime features, all of which have already shipped to chrome. At our current pace, we formally release 4 times a year, for reference, which is actually a far cry from the more continuous deployment browser vendors currently have setup. The main difference is that most people kinda ignore new JavaScript stuff for awhile until it trends or gains sufficient rollout. It's an interesting world - I can't really say that people are actually JavaScript version aware, beyond, maybe, what compatibility presets @babel/preset-env gives them.
- wwwigham 7y agoJavaScript itself keeps changing, so we need to keep pace with that, for one. Beyond that, we relentlessly seek to improve how people interact with our editor tools, and make additions to the (type) language and compiler to support that. .d.ts files from js files, for example, are highly motivated by a desire to better support incremental compilations with .js inputs, as .d.ts files are used as incremental metadata. Assertion signatures were added to better express the cross-call control flow patterns some (assertion) libraries already use, to make using them in a well-typed way more ergonomic. Generally speaking, it's not often we add something that _invalidates_ the old way to do something (in the language) - our additions are usually made to make new patterns possible to express.
- vosper 7y agoThanks for the response. I do appreciate the efforts of the team, and am planning to continue learning TypeScript :) Maybe this exists, but one thing that would be super helpful is a document that explains any places where there's a "new best way" of doing things, and also details what the old way was. Here's an example from yesterday: I was Googling about extending a type (I think) and the first SO result (top of Google) says "you can't do that in TypeScript"... but reading the comments someone had said "actually you can, in 2.6 or later". That's the kind of thing that it would be great to have summarised in one place. Not necessarily all the changes (ie, not just all the release notes) but specifically where the language has changed and an old way of doing things, or a previous restriction, is gone. Preferably with examples. (I'd try to create this, but I don't have the skills to do so).
- wwwigham 7y agoWe actually primarily use StackOverflow for this (as it's the first resource many devs go to, as you did, and it's collaborative). We even pre-seed questions and answers for releases, sometimes. If you find an answer on SO is out of date - suggest a new answer (or ask for one) and get it updated (there's far, far too many for us to keep explicit track of them, there's only a handful of us on the team)! :D
- WorldMaker 7y ago> how do I know that's still the best way to do it in 3.7? Maybe don't worry about the "best" way to do something and use what works? Typescript has really good backward compatibility, it's very rare for something to stop working that previously worked. If it turns out there is an easier way to do something, you'll likely have reason to want to learn it, but at least in my experience with Typescript you'll rarely find a "need" to learn it or your code will break.
- orta 7y agoThere's a bunch of website work that came out with this release too: mainly search and a lot of playground improvements. https://www.typescriptlang.org https://www.typescriptlang.org
- russley 7y agoThis is going to be one of my favorite releases since 2.8, which added conditional types. So many bad utility functions will be able to go away. The only thing it seems to be missing is variadic type generics.
- dashwav 7y agoI really like the new optional operator, this might be what gets me to bite the bullet and start moving some of my projects over to typescript - dealing with potential undefined objects in those chains is one of the things I actively dislike about writing in vanilla Javascript.
- simlevesque 7y agoYou won't regret it ! It helps me every day. Just be sure to not be too strict in your tsconfig.json in the beginning. edit: I'm refering to "noImplicit*" configuration.
- AgentME 7y ago>Just be sure to not be too strict in your tsconfig.json in the beginning. Do you mean to avoid using the "strict" rule, or are you referring to other rules? My number one Typescript suggestion is to make sure you start with "strict": true in your tsconfig.json to be sure your code has nullability correctly enforced.
- simlevesque 7y agoI'm talking about "noImplicitAny", "noImplicitReturns", "noImplicitThis"... they get in my way when I'm editing. When I'm about to push my code I activate them back.
- charrondev 7y agoPersonally I just don’t block the result of my hot dev server on the type checking. I follow along with types in my IDE, and in a separate command. Basically Babel for transpilation (which strips all types, correct or not), and type checking in a separate process.
- notus 7y agoI just use lodash get when I access object properties
- alipang 7y agoGreat incremental release. Typescript really isn't the most exciting language, but it's very very helpful. Compared to regular javascript it saves me a lot of time, and so many pains and headaches every day.
- iLemming 7y agoHa. Try Clojurescript. You'll be surprised.
- huy-nguyen 7y agoOr ReasonML.
- Rapzid 7y agoOr F#.
- findjashua 7y agonow if they can just add a compiler flag for "immutable by default": https://github.com/microsoft/TypeScript/issues/32758 https://github.com/microsoft/TypeScript/issues/32758
- seanwilson 7y agoFor this code: const x = [1,2]; const y = x[666]; const z = y + 3; Is there a way for TypeScript to flag the last line as a type error? TypeScript will say "y" has type "number" when "x[666]" returns undefined. Why does TypeScript not say the type of "y" is "number | undefined"?
- Eyas 7y agoNot really https://github.com/microsoft/TypeScript/issues/9235 https://github.com/microsoft/TypeScript/issues/9235 Though with tuples, etc. being defined, maybe it's worth re-examining.
- seanwilson 7y agoThanks. Is there a pattern for array access that helps with my example? Is the only option to define your own safe access function like "function safeGetFromArray<T>(array: T, index:number): T | undefined"? I haven't tried it yet but it looks like the new optional element access feature is only checking if the array itself is defined, not if the array index is defined.
- emptysea 7y agoI can't seem the find the GitHub issue for it off hand, but I believe you can override the default indexing signature for arrays to return possibly undefined. Otherwise, you're left to creating a wrapper function and a custom ESlint rule. Edit: found it https://github.com/microsoft/TypeScript/issues/13778#issuecomment-277029664 https://github.com/microsoft/TypeScript/issues/13778#issueco... The suggestion is to maintain your own copy of `index.d.ts` with the array indexing interface modified. Yikes!
- jakelazaroff 7y agoFor array types, I don't think there's a way. You can type x as a tuple like this: const x: [number, number] = [1, 2]; In which case you'll only be able to access indices zero and one.
- 7y ago
- wayneftw 7y agoOptional Chaining also coming soon to create-react-app, planned for v3.3 (current release is react-scripts@3.2.0) - https://github.com/facebook/create-react-app/pull/7438 https://github.com/facebook/create-react-app/pull/7438 I think they're just waiting on support for the new syntax in prettier.
- ljm 7y agoIs it not bizarre that you're blocked on a syntax formatter to make a release? If that's what's happening, it sounds like prettier should be core and non-optional, the same way gofmt is.
- breatheoften 7y agoYou can’t live without prettier once your using it.
- andy_ppp 7y agoEverything should be perfect of course, Javascript is a compromise. I’d say Golang should have a few extra features included too I dare say :-)
- eduren 7y agoThe commenter was talking about a release of create-react-app, which is a starter-kit/scaffold. For such a project with the goals of being a packaged collection of tools/configurations, it seems prudent to only release if your set of tools present a consistent experience. Many js developers see formatters as a sane default, and create-react-app is a layer in the ecosystem that incorporates it as a "core" piece in the way that you meant above.
- SirensOfTitan 7y agoI feel really excited about 3.7. Optional chaining and null coalescing will clean up a TON of code. ... but with that being said, 3.7 seems to have broken many aspects of the `Promise.all` interface. Right now the largest issue seems to be that if any `Promise` result in `Promise.all` is nullable, all of the results are nullable.
- nine_k 7y agoIndeed, how can you declare a list with some elements nullable, and some not? The result should instead be a tuple, but IDK how well tuple size inference would work in a case like that.
- 52-6F-62 7y agoI’m not at a computer now, but you can explicitly define a tuple type like: type Tuple<T, K> = [T, K | null]; Which is my first thought, but I can’t test it against the compiler at the moment and I’m not sure if I’m missing something. ...JavaScript would allow you to extend that list during runtime (unless you freeze it) type Tuple<T, K> = [T, K] const Tuple<T, K> = (x: T, y: K): Tuple<T, K> => { const tup = [x, y]; Object.freeze(tup); return tup; };
- amaranth 7y agoHaving it be a tuple would require variadic generics, wouldn't it?
- Klathmon 7y agoThis is a moment where the postfix `!` operator comes in handy. It is a well hidden secret, and one that I'm not going to try to lookup the docs for on mobile, but the idea is that the operator strips null/undefined from the type of whatever is before it. So you can do something like this: const [ a, b ] = await Promise.all([ async () => ({ foo: 'bar' }), () => null ]) console.log(a!.foo) // `a!` strips the nullable off `a`
- 7y ago
- deleted 7y ago[deleted]
- koolba 7y agoDoes the function argument (i.e. the template string) get evaluated regardless of the optional chaining or does it match up with the “roughly equivalent” code? log?.(`Request started at ${new Date().toISOString()}`); // roughly equivalent to // if (log != null) { // log(`Request started at ${new Date().toISOString()}`); // }
- deleted 7y ago[deleted]
- sceutre 7y agoThe latter. You can look at what javascript is emitted on the playground. let bar: any, log: any; log?.(`foo ${bar()}`); // becomes var _a; var bar, log; (_a = log) === null || _a === void 0 ? void 0 : _a("foo " + bar());
- sicromoft 7y agoWhy would it not match up with the example given? They provided it so you'd know the answer to your question.
- koolba 7y agoI copied the example from the article but it says “roughly” so it’s not entirely clear. The situation that popped in my mind was something like: f?(++a) Normally you’d expect the side effects incrementation to occur prior to the start of the function invocation. If the function is not evaluated it’s not clear from the article if increment will occur.
- plexicle 7y ago`?` will short-circuit. Nothing is evaluated after that.
- munificent 7y agoThe optional chaining and null coalescing operators are very nice. Dart has had those for several years and they really do come in handy.
- grapehut 7y agoDefinitely. It's a shame that dart gets so much unwarranted hate. I mean, I also think it's an absolutely awful language but it's really proven to be a valuable source of data for what other programming languages should do and perhaps more importantly: not do. I really hope we see a lot more things like Dart, and not so much negativity.
- lucasmullens 7y agoI haven't heard this general hatred of Dart. Why do you think it's an absolutely awful language?
- nsonha 7y agonot awful, more like mediocre and has no reason to exist
- munificent 7y agoDepending on when you last looked at Dart, there's a good chance we've either fixed or are fixing the things you hate about it. What didn't you like?
- virtualwhys 7y ago> What didn't you like? That the suggested features in this open issue [1] can't be implemented soon enough :) Is there a roadmap available that would give an idea as to when x, y, z language features may be implemented? [1] https://github.com/dart-lang/language/issues/546 https://github.com/dart-lang/language/issues/546
- 7y ago
- XCSme 7y agoVery cool features for writing shorter code! I also noticed a small mistake in their examples: https://github.com/microsoft/TypeScript-Handbook/issues/1135 https://github.com/microsoft/TypeScript-Handbook/issues/1135
- shhsshs 7y agoGood catch!
- nikeee 7y agoI really like the optional chaining operator for statically typed languages. Especially in TypeScript where you have the nullabilaty information baked into the type system. However, in JS itself, it might cause developers to lose track of what can be null/undefined in their code. In case they start to "fix" stuff by throwing in some "?." because they don't know better, the code maintainability will degrade a lot. Maybe I'm just pessimistic. Let's see how it will perform in the field!
- nicoburns 7y agoIt's nice for situations where you want to access a deeply nested prop, and you only care whether the whole path is there or not. Saves you having to add a seperate check for every level of the hierarchy. e.g. You can do: foo?.bar?.baz || "default"; Rather than: (foo && foo.bar && foo.bar.baz) || "default"; Agree that developers can be careful about nullability (in fact I pulled someone up on this in a code review earlier today), but I don't think this feature makes that any worse.
- nikeee 7y agoIt came to my mind because I've seen some Angular templates (they had this syntax before TypeScript had) where the dev just threw in some "?." to fix only the symptoms of a bug. This resulted in some ngIf condition to be always falsy and never showing a specific element. The real bug was that the property in question should never be null/undefined in the first place. It was a lot harder to find the error. Also, I've seen some typos (or missed renames) being unnoticed without any errors. This caused some weird behavior in the frontend where there was no exception but there is definitely something wrong. Or, worse, the bug is never noticed and other code depends on that behavior. So if the language is statically typed, the feature is awesome because the cases mentioned above will trigger a compile time error. I've seen some misuse in dynamically typed ones.
- wilsonrocks 7y agoI'm excited to take out a lot of lodash gets
- 7y ago
- dstaley 7y agoI'm super excited about this release, but it got off to a rocky start for me. Prior to 3.7, all our tests worked fine, but something in 3.7 changed that caused the type-checker to fail previously valid code. What's worse is that I can't reproduce the issue in a playground. Thankfully the workaround is "make your code more explicit", which is fine, but it was just a surprise to see something like this break. For those that are curious, here's the error that 3.7 introduced: Type 'SinonStub<[string, RequestBody, (RequestOptions | undefined)?], KintoRequest>' is not assignable to type 'SinonStub<any[], any>'. Type 'any[]' is missing the following properties from type '[string, RequestBody, (RequestOptions | undefined)?]': 0, 1 I think the issue here is that `[string, RequestBody, (RequestOptions | undefined)?]` is a tuple type, and `any[]` is an array type. That being said though, I'd expect that a tuple would satisfy a `any[]` type.
- dickeytk 7y agoKeep in mind that TypeScript does make breaking changes in point releases. They don’t ascribe to semver. Not sure if that’s your issue or a bug though
- rraval 7y ago> That being said though, I'd expect that a tuple would satisfy a `any[]` type. You have it backwards, the error in question is complaining that `any[]` does not satisfy the tuple type. Minimal repro: function f(x: any[]): [number, string] { return x; } The error matches yours: Type 'any[]' is missing the following properties from type '[number, string]': 0, 1 From poking the playground, `any[]` hasn't been assignable to tuples since at least v3.3.3 My guess is that the compiler got smarter around reasoning about your `SinonSub` generic and is now forcing you to deal with lingering unsoundness.
- dstaley 7y agoYeah, that's my assumption as well. It would explain why there's no mention of it in breaking changes, and why being specific about the generics in `SinonStub` fixes the error. Makes me wonder what other unsoundness the compiler isn't catching.
- achou 7y agoI just did some refactoring on a medium size code base and here are a few things to watch out for when adopting optional chaining and the new null coalescing operator: foo && await foo(); is not the same as await foo?.(); this will work in most cases but subtly, the await wraps the undefined case into a Promise, while the original code would skip the await altogether. String regular expression matching returns null, not undefined, so rewriting code such as: const match = str.match(/reg(ex)/); return match && match[1]; is not the same thing as: return match?.[1]; because the latter returns undefined, not null, in case of match failure. This can cause problems if subsequent code expects null for match failure. An equivalent rewrite would be: return match?.[1] ?? null; which is longer than the original and arguably less clear. A common idiom to catch and ignore exceptions can interact poorly with optional chaining: const v = await foo().catch(_ => {}); return v?.field; // property 'field' does not exist on type 'void' This can be easily remedied by changing the first line to: const v = await foo().catch(_ => undefined); Of course, these new operators are very welcome and will greatly simplify and help increase the safety of much existing code. But as in all things syntax, being judicious about usage of these operators is important to maximize clarity.
- mattigames 7y agoYou have to watch out for first and last one in JavaScript but not on TypeScript as it isn't possible to make that mistake because you have to type it as a promise or in the last one as void. You can even avoid the problem in the second one by using NonNullable TypeScript types, but I admit that's not common so its still likely to arise.
- achou 7y agoThe first example can happen in TypeScript; foo has type (() => Promise<void>) | undefined admittedly it may not be all that common to have a function-valued variable that may be undefined, but it happened in the code base I was working with. In the last example, you're right that TypeScript will catch this at compile time. My point was to show how this compile time error can happen from refactoring to use optional chaining, and one easy solution in this case.
- 7y ago
- reggieband 7y agoI'm a big fan of the new operators. One of my remaining gripes with Javascript/Typescript is the try/catch mess around await. It makes assignment of const a pain for async calls that may reject. e.g. let result: SomeType; try { result = await funcThatReturnSomeType(); } catch (err) { doSomethingWithErr(err); } // at this point result is `SomeType | undefined` if (result) { doSomething(result); } I really want some kind of structures that allow me to make `result` constant. In some cases I've rolled my own Maybe/Either wrapper and then move the try/await/catch into a function but that is still a pain. This is such a common pattern in my code ... I wish there was a more elegant way to deal with it.
- isthisreality 7y agoThere's this keyword called "var"
- 52-6F-62 7y agoI’ve run into the exact same situation and continue to repeatedly. In fact this is a stupidly common pattern in a library in working on at work right now. My solutions have involved casts (and comments explaining the assumptions involved) instead of the ‘if’ statement more times than I’d like to have done, but it ends up with the same result with the added (however small) compute with the conditional since it can be safe to assume the value is not undefined. It’s not perfect, but it at least omits unnecessary runtime code.
- knocte 7y agoFrom the snippets in the release notes: ``` function dispatch(x: string | number): SomeType { if (typeof x === "string") { return doThingWithString(x); } else if (typeof x === "number") { return doThingWithNumber(x); } process.exit(1); } ``` It's very embarrassing in my opinion that they haven't done anything yet against having these horrible kind of type checking; comparing against a string that has the type name? "string", "number"? it's completely ludicrous. I will not take this language seriously until this is fixed. (For sure it's still better than JavaScript, but that's about it.)
- MaulingMonkey 7y agoYou can define your own type guards: function isString(x: any): x is string { return typeof x === "string"; } function isNumber(x: any): x is number { return typeof x === "number"; } function dispatch(x: string | number): SomeType { if (isString(x)) { doThingWithString(x); } else if (isNumber(x)) { doThingWithNumber(x); } process.exit(1); } TypeScript seeks to manage JavaScript's horrors, but importantly, it does not seek to hide them behind leaky abstractions. This is not an embarassment, but TypeScript's strength and weakness. There is a long list of other languages that compile down to JavaScript or WASM, if you want a language built from clean foundations. But if you want to add gradual typing as a means of slowly reigning in your existing JavaScript behemoth? There is only one TypeScript.
- Diesel555 7y agoOptionals! I wrote Swift before typescript, and I'm a huge fan of these new operators.
- macca321 7y agoNow I know how people felt when they told me C# was adding features so quickly they couldn't keep up.