News for hackers. Stuff that matters.
Re:TypeScript 3.5 by KenanSulayman on Wednesday May 29, 2019 @03:46PM (#20044540)
I second that, to a degree. I write mostly TypeScript and Rust these days and it still behaves unexpectedly sometimes.

Example: for a service we wanted to port Rusts’ Result.

https://gist.github.com/KenanSulayman/34a40daa3ebbd1e1bdf7c7...

Notice the ‘as any’ and ‘_T!: T;’ et al. hacks to make it work.

Other than that it’s completely a one to one port from the Rust core implementation.

Re:TypeScript 3.5 by wereHamster on Wednesday May 29, 2019 @04:17PM (#20044879)
Because you're trying to manually optimize code, which is kindof like saying 'I konw what I'm doing so TypeScript please shut up'. Take for example the `map_err` function of the `Ok` class. The function returns a different `Result`, but you're using the `… as any` trick to shut up the compiler. The correct implementation would be:

    map_err<U>(fn: (arg: E) => U): Result<T, U> {
        return new Ok<T, U>(this.value)
    }
I see why you're not doing that, because that allocates a new object, and that might seem bad. Even the implementation in Rust 'allocates' a new object, but then it relies on the rust compiler to optimize that out. Here's the relevant code:

    pub fn map_err<F, O: FnOnce(E) -> F>(self, op: O) -> Result<T,F> {
        match self {
            Ok(t) => Ok(t),
            Err(e) => Err(op(e))
        }
    }
See the `Ok(t) => Ok(t)` line? That's the same as `return new Ok(…)` in the TypeScript code. Unfortunately TypeScript is not an optimizing compiler, so it's less powerful than rust. You can either use tricks (`… as any`) and give up type safety or be truthful at the expense of performance.
Re:TypeScript 3.5 by steveklabnik on Wednesday May 29, 2019 @04:21PM (#20044928)
To be clear, the option type in rust does not heap allocate at all; no need for the compiler to optimize things away.
Re:TypeScript 3.5 by phiresky on Wednesday May 29, 2019 @04:40PM (#20045181)
Your problem there seems to mostly be that you tried to directly port it without any modifications, and your code is actually incorrect in some places. For example, if you implemented Result<T, E> as a single class that had a `if(this.is_ok()) ...; else ...` it would work fine without any type assertions or any anywhere.

As it is, Ok only depends on T and Err only depends on E, so why do you have them depend on both?

One problem is that TS does not want to merge unionized function signatures like this:

    map: (<U>(fn: (arg: "yep") => U) => Ok<U>) | (<U>(fn: (arg: any) => U) => Result<U, "nope">)
This can be mostly fixed by removing arguments that you don't need.

I couldn't figure out .map_or_else, but .map().or_else() works.

Admittedly, with this way you can get an output of Ok<a> | Ok<b> from some functions, but I don't know where that would be a problem (still fully type checked, you would just get the expected error further outside.

Here's a updated gist: https://gist.github.com/phiresky/621f8d8ed6eb00c9a0ddb47217e...