News for hackers. Stuff that matters.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by Waterluvian on Sunday December 25, 2022 @09:18PM (#34133838)
I just want the map, reduce, filter functions to be acutely aware of the narrowed types. The moment I use Object.entries and then work on the data, the key has been widened to string.

Okay and maybe I also want it to be aware of type assertions that happened outside the array functions. You should already know that x cannot be undefined anymore. I tested that. I know you don’t think you can be sure you’re actually being called after the assertion, but you are! It’s obvious!

Oookay and maybe just one more (sorry Santa!): I want a ‘pure’ keyword. Any function that is pure can only call functions that are also keyworded as pure. No side effects, guaranteed.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by HellsMaddy on Sunday December 25, 2022 @10:02PM (#34134103)
I love the pure function idea.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by mpoteat on Sunday December 25, 2022 @10:21PM (#34134207)
You can implement a type-aware map, reduce, filter, etc. if you use point free semantics with higher kinded types:

https://code.lol/post/programming/higher-kinded-types/

I have to admit it's a bit heavy, but this is totally representible in today's Typescript if I understand your ask correctly. It would be great if it was a more obvious / automatic inference, though.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by tadfisher on Sunday December 25, 2022 @10:22PM (#34134217)
The opposite would be better: an "impure" keyword for specifying impure functions.

Or maybe, you could pass some kind of "scope" interface that provides functions for executing side effects. So "impure(IO) function printStuff()" brings all the functions in IO into scope for the body of printStuff.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by castrodd on Sunday December 25, 2022 @10:26PM (#34134239)
Why would the opposite be better? Aren't most functions impure? The original proposal made sense to me, but I am curious as to why you believe impure is better. Can you elaborate?
Re:All I Want for Christmas Is These Seven TypeScript Improv... by andreareina on Sunday December 25, 2022 @11:24PM (#34134569)
Pure being the default would lead to most functions being written to be pure. Same idea as immutability by default.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by jonas21 on Monday December 26, 2022 @01:07AM (#34135111)
One of the best things about TypeScript is that you can adopt it incrementally, i.e. valid Javascript is also valid TypeScript. For that to work, you have to assume functions are impure by default.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by goto11 on Friday December 30, 2022 @07:48AM (#34184519)
> Pure being the default would lead to most functions being written to be pure.

More likely it would lead to most functions looking like they are pure, whether they are actually pure or not.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by noduerme on Sunday December 25, 2022 @11:12PM (#34134508)
Deducing types from Object.entries would be pretty awesome. That would feel like black magic. I had a lot of fun messing around with Copilot seeing if it could guess exactly that kind of thing, sometimes directly from raw results of SQL queries once it understood the DB table structure. Occasionally it could. (Nonetheless, I don't feel like paying for it).

Still, it feels dangerous to be able to feed a generic object method in and expect the return to be typed based on a previous typing of the composite instances. Or maybe it feels like something that should always pass a compile check - because Object.entries can always be any - and only fail at runtime. Even if it was a feature, it's something I wouldn't implicitly trust a compiler to catch all edge cases of.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by TheCleric on Monday December 26, 2022 @07:07PM (#34143334)
> Deducing types from Object.entries would be pretty awesome. That would feel like black magic.

Not really. Typescript already has the

  keyof
keyword. For some reason though

  Object.entries(T)
returns

  string[]
when it could easily return

  keyof typeof T
I've had to write a helper function that essentially does this for you with a generic and a cast, but it feels unnecessary.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by siwatanejo on Sunday December 25, 2022 @11:33PM (#34134621)
> I want a ‘pure’ keyword. Any function that is pure can only call functions that are also keyworded as pure. No side effects, guaranteed.

It's better to default to the best practice. What you should wish is for an `impure` keyword and then all impure functions that are not marked as such would raise a compiler warning.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by Volundr on Sunday December 25, 2022 @11:42PM (#34134666)
I agree that'd be better, but that ship has long since sailed. I for one specifically don't wish for that because a breaking change like that would create a new python 2/3 situation.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by goto11 on Monday December 26, 2022 @08:31AM (#34137458)
Doesn't fit with the Typescript philosophy though: It should be possible to gradually add Typecript annotations to existing JavaScript code. It wouldn't work with 3rd party libraries either.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by Waterluvian on Monday December 26, 2022 @09:55AM (#34138042)
I agree that it’s not practical. Ship has sailed a long time ago.

But one solution might be a “noImplicitImpure” option.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by goto11 on Monday December 26, 2022 @11:08AM (#34138814)
Still wouldn't work, since there is no way for the compiler to distinguish between a pure function and an impure function which just don't have an annotation - e.g. a third-party library written before "impure" was introduced to the language.

If pure functions were explicitly marked as "pure" the compiler could just conservatively assume all other functions were impure. But the opposite does not work.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by Waterluvian on Monday December 26, 2022 @01:19PM (#34140232)
Oh. You’re right. The moment you turn that flag on, it can’t complain the away implicitAny can. Therefore you need “pure” rather than “impure.”
Re:All I Want for Christmas Is These Seven TypeScript Improv... by nawgz on Sunday December 25, 2022 @11:56PM (#34134727)
> the moment I use Object.entries ... the key has been widened to string

This is correct behavior though, and what you propose would be wrong. The type isn’t narrowed. Type U satisfies type T when the keys of U are a superset of the keys of T, so long as the keys map to the correct value-types in the intersection of (keyof T) and (keyof U)

This is because the only time extra keys are outlawed is when you instantiate an object of type T and explicitly declare it as a T. I can link if you need but this is an important subtlety which is why Object.entries returns string instead of keyof T, and it’s not borne of MS/TS developer laziness

Re:All I Want for Christmas Is These Seven TypeScript Improv... by Jacqued on Monday December 26, 2022 @05:02AM (#34136283)
You’re right about how it works today but it seems to me this is an odd choice to make. Why not enforce object types?

Could they add a strictness flag that lets objects actually be type safe and enables related functions to work out of the box? For me this stuff is a regular pain point as you end up typecasting at every call site :(

Re:All I Want for Christmas Is These Seven TypeScript Improv... by nawgz on Monday December 26, 2022 @06:16PM (#34143013)
> Why not enforce object types?

It would be incredibly painful to write idiomatic JS with constant narrowing required and would lead to huge performance issues.

Imagine you write some generic sort capabilities, sorting by label, createdDate, etc., and then you declare some types

    interface SortableByLabel { label: string }
    interface SortableByCreatedDate { createdDate: Date }
    ...
Then you implement a method

    function sortByLabel(a: SortableByLabel, b: SortableByLabel) { ... }
I've written enough, I think you can see how easily this works today and how painful and un-performant it would be to do this if you had to narrow your objects or constantly write extra info into your types to allow them to not enforce narrowing, and then there's a whole can of worms around your "widen"-able object types being illegal to functions that require exact types, ...

Instead you can just write arrays...

    interface MyInterface {
      key1: Type1;
      key2: Type2;
      ...
    }

    const myKeys:Array<keyof MyInterface> = [
      'key1',
      'key2',
      ...
    ] as const;

    function operatesOnKeys(object: MyInterface) {
      // don't use Object.entries...
      myKeys.forEach((key) => {
        object[key];
        // TS is happy, and bonus:
        // this will be type checked later if MyInterface changes
      });
    }
I think TS has some issues but this isn't one of them.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by commotionfever on Monday December 26, 2022 @12:05AM (#34134769)
for the situation of filter, map, then knowing x is present, there is

https://www.npmjs.com/package/ts-is-present

that particular case is a small snippet but the package also comes with helpers for reaching into objects to do a similar thing

Re:All I Want for Christmas Is These Seven TypeScript Improv... by CGamesPlay on Monday December 26, 2022 @12:21AM (#34134831)
> I want a ‘pure’ keyword. Any function that is pure can only call functions that are also keyworded as pure. No side effects, guaranteed.

Pipe dream, unfortunately. If pure functions accept objects as arguments, those objects could have impure getter methods, or perhaps be proxy objects that have impure methods. Pure functions could also receive Function objects, so you'd have to indicate that the passed arguments are pure as well.

Unfortunately, because TypeScript is optional, such a declaration on the functions and their arguments would also be optional, meaning that you couldn't even rely on this as a language feature (your caller could pass you an impure function even if you specified you didn't want it).

Re:All I Want for Christmas Is These Seven TypeScript Improv... by 411111111111111 on Monday December 26, 2022 @01:01AM (#34135070)
I'm not sure how much value such a feature would have, but both of your points are already addressed by the original wish. A passed in callback would have to be pure too and a getter function couldn't be called unless it's marked pure too. WebStorm already colors property access differently then the custom getter, why wouldn't Typescript be able to differentiate?

Your last argument is confusing: the same applies to everything in typescript. You can also pass in a string to a field that's demanding a number by using "as" so you never have any type guarantees in TS, there is value in it nonetheless.

And the same would surely apply to pure functions (I.e. inpureFunction as PureFunction)()...) It could still be a valuable feature anyway

Re:All I Want for Christmas Is These Seven TypeScript Improv... by CGamesPlay on Monday December 26, 2022 @01:40AM (#34135323)
Any property access could be a getter function, and TypeScript doesn't know which properties are getters and which aren't [0]. Similarly for Proxies, anything could be a proxy and the design goal of Proxies is that they cannot be differentiated from regular values.

But imagine that TypeScript in addition to pure functions you can also tag objects as "POD objects" or "JavaScript objects". The POD ("plain old data") objects can't be proxies or have impure getter methods, and only POD objects can be passed to pure functions. The "pure" keyword actually means "pure if all arguments are POD objects" (this is to avoid having to write N purity overloads for an N-ary function).

You want to call a pure method from your impure method, and pass it one of your arguments. Your arguments now need to be declared to be POD objects, which means they are incompatible with the rest of your code base. This has to go all the way up... it's basically "colored functions" except it's colored objects this time, and the colors are completely incompatible (async functions can call sync functions, but impure functions can't call pure functions with impure arguments, and pure functions can't call impure functions at all).

[0] https://www.typescriptlang.org/play?#code/C4TwDgpgBAkgYgewVA...

Re:All I Want for Christmas Is These Seven TypeScript Improv... by 411111111111111 on Monday December 26, 2022 @03:43AM (#34135888)
> Any property access could be a getter function, and TypeScript doesn't know which properties are getters and which aren't

I'm aware. That doesn't make it impossible to differentiate as Webstorm shows by coloring the bar differently for fooA vs fooB in your example. But yes, it would have to be implemented as part of that pure feature.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by kevingadd on Monday December 26, 2022 @01:15AM (#34135153)
All properties are potentially getters and any value can be a proxy.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by delaaxe on Monday December 26, 2022 @03:49AM (#34135914)
The point is about only being able properties marked as pure with special syntax, whatever their implementation
Re:All I Want for Christmas Is These Seven TypeScript Improv... by kevingadd on Monday December 26, 2022 @11:30AM (#34139094)
If a compiler makes safety guarantees that aren't actually guarantees, like "this function is pure because you made some naive promises you can't keep", it undermines your ability to rely on any of the verification it does.

It's especially bad to do this if you're going to perform optimizations based on those safety guarantees (thankfully, typescript doesn't do that.) You can say 'don't use the pure keyword then' but the fundamental design of JS means that in practice almost no functions can be pure. The runtime has to identify cases on the fly where pure optimizations are actually valid.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by Waterluvian on Monday December 26, 2022 @01:17PM (#34140208)
Isn’t that the model of TypeScript though? If your code ever brings in data from an outside source, somewhere in it you’re saying, “trust me, it’s typed as X.”

Though now I’m doubting myself because maybe it’s possible to use complex enough assertion functions to really prove that. But even if you don’t, it’s still an incredibly useful language. You’re basically saying, if X is true then the rest of this program should fit together like so.”

Re:All I Want for Christmas Is These Seven TypeScript Improv... by kevingadd on Monday December 26, 2022 @02:09PM (#34140711)
Right, the thing is that a lot of typescript's assertions are valid even without complete top to bottom knowledge of the code being executed. Object shapes, for example, are pretty clean to reason about (proxies do complicate this some, but not nearly as bad as they do purity), which means structural typing stuff can just work. It doesn't matter whether property 'x' is a getter or a value as if all you need to know is whether an object has a property named x, and if you need to know the type that also is something you can check without needing to know whether reading the value has side effects. And shapes/types can be verified at runtime as long as state isn't mutated between verification and use.

You're right that in the end once you pull in outside data you're having to make promises that you may not be able to keep - I just think purity is an especially difficult set of promises to keep, and the existence of proxies and getters in JS (along with how they work) makes purity basically impossible, so it's just a footgun waiting to be used. And TS isn't going to optimize your code using it, so it's not really delivering value either.

Re:All I Want for Christmas Is These Seven TypeScript Improv... by delaaxe on Saturday December 31, 2022 @05:48PM (#34201554)
Proxies and state-mutating getter functions are pretty edge features of JS tbh
Re:All I Want for Christmas Is These Seven TypeScript Improv... by culi on Monday December 26, 2022 @01:06AM (#34135107)
doesn't `readonly` solve this already?
Re:All I Want for Christmas Is These Seven TypeScript Improv... by gpgn on Monday December 26, 2022 @01:42AM (#34135344)
"pure" in the context of functional programming often means "without side effects", so writing a log file, interacting with a database and so on would also make the function not pure
Re:All I Want for Christmas Is These Seven TypeScript Improv... by culi on Monday December 26, 2022 @06:33AM (#34136806)
fair enough, thanks
Re:All I Want for Christmas Is These Seven TypeScript Improv... by throwawaymaths on Monday December 26, 2022 @12:40AM (#34134927)
The reason you don't want a pure keyword is because suppose you're doing some sort of stateful mock. Or, maybe you have a configuration that start outs having a fixed compile time lookup in a passed data structure, but then you evolve it to where it looks it up via a web service. If you were making assumptions that it was pure in either situation, your refactoring is going to be crazy painful.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by antihero on Monday December 26, 2022 @03:54AM (#34135943)
Highly recommend rambda, the types are better than the native functions.
Re:All I Want for Christmas Is These Seven TypeScript Improv... by davedx on Monday December 26, 2022 @04:05AM (#34135995)
Yea - filter especially doesn’t seem to work so well when you filter out null/undefined values then chain to another map
Re:All I Want for Christmas Is These Seven TypeScript Improv... by akdor1154 on Monday December 26, 2022 @04:48AM (#34136192)

    [1,2,undefined,3]
    .filter(<T>(x: T|undefined): x is T =>
        typeof x !== 'undefined'
    );
Yes builtin lang support would be better, but that gets you out of trouble in a pinch, without adding more 5 line npm baggage.

N.B. if you are in a JSX file, you'll need to add a comma: `<T,>`

Re:All I Want for Christmas Is These Seven TypeScript Improv... by kaleidawave on Monday December 26, 2022 @05:57AM (#34136590)
Ezno a semi compatible TypeScript compiler does effect tracking. It’s possible but you do have to handle the way functions handle parameters which is why it’s type system is different to the way tsc handles things. And for functions outside of the user code you have to know what effects are internally run. Things like JSON.stringify look pure until you pass it an object who has a toJSON method that does something silly. A little complicated to show what stringify internally does but possible if you add additional metadata to the definition files.

Then rather than marking a function as pure you instead check it is pure by looking at what effects its function type has!