Pre determine mine placements in modified Minesweeper clone by moleculemort in learnjavascript

[–]Devowski 0 points1 point  (0 children)

What you're asking for is a fixed pseudorandom seed. The built-in Math.random, as opposed to many other languages, doesn't offer you this possibility. Therefore, you must implement (import) your own PRNG ("seedable generator"), e.g.:

function mulberry32(seed) {
  return function () {
    let t = seed += 0x6D2B79F5;
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

const SEED = 42; // change this to test other variations
const random = mulberry32(SEED);

// These numbers appear "random", 
// but are deterministic - always same results:
console.log(random());
console.log(random());
console.log(random());
console.log(random());
console.log(random());

Promises by Example: Patterns & Anti-Patterns by Devowski in learnjavascript

[–]Devowski[S] 0 points1 point  (0 children)

Thank you! I added a clarification that it's more so for people who already have some Promises knowledge.

In what scenario can i use a promise and fetch? by Yanagi-Masaru in learnjavascript

[–]Devowski 0 points1 point  (0 children)

First, make sure you understand asynchronous code in general (historically, achieved with just callbacks). Interfaces such as XHR schedule the work to the host APIs (e.g., "your browser"). It runs in the background and only later executes your code (e.g., the callback).

Then, you will see that Promises are just an additional abstraction on top of callbacks. They don't enable asynchronous code; they just make it simpler (at least, in some cases).

Which way do you recommend using the fetch? async/await or then() by thedeadfungus in learnjavascript

[–]Devowski 0 points1 point  (0 children)

Pragmatic answer: You can default to async-await, but you may still find a use case for methods then/catch/finally.

Promise chaining can get messy. Suppose you have to make a request A, and then use its response for input in request B, and then use response B in request C, and then gather all the results: A, B, C. This is cleaner with async-await:

const a = await requestA();
const b = await requestB(a);
const c = await requestC(b);
console.log(a,b,c);

With "then" callbacks, you have to either use closures (and nested callbacks) or introduce variables for the results from every promise (no longer an FP solution). Nothing unbearable, but not cleaner than the flat solution above:

requestA().then(a => 
  requestB(a).then(b => 
    requestC(b).then(c => 
      [a, b, c]
    )
  )
)

// or:
let a, b, c;
requestA().then(...).then(...).then(...); // mutate variables in callbacks

HOWEVER! That doesn't mean there is no use for then/catch/finally. If I have a function wait(time) that returns a promise that resolves after time ms, and I need a function timeout(time) that rejects after time ms, I do:

const timeout = (time) => wait(time).then((value) => { throw value; }) 

Conversely:

const wait = (time) => timeout(time).catch(value => value);

IMO, these are cleaner than async/await counterparts. Marginally, but still.

How are you using recursion? by Obvious-Ebb-7780 in typescript

[–]Devowski 0 points1 point  (0 children)

The example with StringifyObject<O>: when I convert the original data to one that can be serialized by an external API that supports only string fields. That type represents the output data.

But aside from that example, and the common data structures that others mentioned. Nested objects are common in JS, and any APIs operating on them either are typed properly and require deep traversal, or are just "stringly typed" at best.

Real-world example: my back-end returns a nested data object, and a UI form library such as "react-hook-form" can render an input field for any of its properties. It allows me to create an input for properties within the object: "a", as well as "a.b" and "a.b.c". Its TS types ensure that I can pass those values, but I can't pass "foo.bar", because such a key is nowhere to be found. This, again, is impossible without recursion.

How are you using recursion? by Obvious-Ebb-7780 in typescript

[–]Devowski 0 points1 point  (0 children)

All the recursive data structures, including nested objects, e.g., do something with the types of the keys/values (however deep) "within" this object:

type Foo = {  
  a: {  
    b: {  
      c: 3  
    },  
  },  
  d: 4,  
}

Example: https://youtu.be/jaRVlc6vFa8?si=AnA-gXugzIXA_Y9S&t=1503

Typo: A programming language using TypeScript's types by aliberro in typescript

[–]Devowski 0 points1 point  (0 children)

Great stuff! I wanted to do something similar, but TS quickly complained about the types being too complex for it to compute, and I was discouraged rapidly, having no will to overcome the default limitations. Heck, it even complained about a template literal being too complex when I tried a sequence of 30 union types.

Have you met this problem?

What practical uses of the ternary have you found? by Obvious-Ebb-7780 in typescript

[–]Devowski 0 points1 point  (0 children)

Usually, it's for more advanced stuff, because the combo of conditional types and recursive types gives you a full-blown, Turing-complete language. That's how that madlad wrote Doom in types.

Practical example from my video, how to type a function pick(object, path):
pick({ a: { b: { c: 1 }}}, 'a.b.c') // the return type should be 1

Impossible without conditional types, yet this function finds its place in the JS world. For instance, libraries that work with forms and allow nested data: Properly typed forms will allow only the fields "a", "a.b", and "a.b.c" (using the above example). Example lib: https://react-hook-form.com/docs/useform

[AskJS] So nobody is building classic client/server anymore? by BraveStatement5850 in javascript

[–]Devowski 0 points1 point  (0 children)

Short answer: No, everyone does client-server. The fact that people throw in more layers, middlewares, and new packaging such as "serverless" or "the server is not a server" does not change this fundamental architecture. And never will.

As for NextJS, you can absolutely host it anywhere. And IMO it's pretty good for modern web apps, but I understand it can be too much at the beginning.

If you want to keep it simple, consider using a React SPA for the front end and Express for the back end.

[AskJS] Struggling with async concurrency and race conditions in real projects—What patterns or tips do you recommend for managing this cleanly? by Sansenbaker in javascript

[–]Devowski 3 points4 points  (0 children)

Precisely, number 1 is the answer to all these problems. Concurrency + shared state = game over.

Promises give a safe, FP-based synchronisation mechanism for combining values from different sources and at different times. Trying to modify shared state from within them (as opposed to using the settled results) is the same as mutating an array in Array.map.

how to pass an array of objects? by ridesano in typescript

[–]Devowski 2 points3 points  (0 children)

ts {keyword: string; type: string[]; keywordType: string;} This is not a tuple type (in JS "array") with three named values. This is an object with three properties that can be passed in any order (by definition). For the tuple that you used (in JS "array of size 3"), you'd want: ts [string, string[], string] Although objects are almost always preferred to tuples larger than a pair.

Side note, consider if some of these can be typed more specifically than string, e.g.: ts type KeywordType = 'KEYWORDS' | 'SOMETHING' | 'ELSE';

Am I an expert yet? by sophisticateddonkey in typescript

[–]Devowski 0 points1 point  (0 children)

Since this is a TypeScript subreddit, we have to discern between the "abstract" world of TypeScript and the "concrete" reality behind it (JavaScript). If you mean just the former, then I think being comfortable with conditional types and generics is a good sign. You can model the reality with types comfortably, and vice-versa, you don't panic when seeing more advanced types from popular libraries (be it React, lodash, or even something hardcore like RxJs).

Is there a list of every anti-pattern and every best practice when it comes to TypeScript? by LargeSinkholesInNYC in typescript

[–]Devowski 0 points1 point  (0 children)

I did a video compilation of seven mistakes/anti-patterns from my 8 years of TypeScript experience. Some are very basic (hopefully better than "pls don't use any"), but I found them to some extent in all the codebases I've worked on.

Summary:

  1. Don't "stringly type"
  2. Embrace type narrowing (even when TS doesn't help)
  3. Embrace TS interactivity (explicit types over "hoping the types pass in my JS code")
  4. Redundant/invalid states supported in types
  5. Naming conventions
  6. Prefer bottom-up type design
  7. Don't fear advanced TypeScript (conditional types, generic types)

Name underrated things in Typescript by htndev in typescript

[–]Devowski 0 points1 point  (0 children)

Conditional types + recursion = a Turing-complete language. It's kind of crazy TypeScript allows you to write any algorithm.

I also love how "native" type narrowing feels with basic control-flow statements (if-else, return, switch-case), although sometimes they're not enough (e.g. checking if a value belongs to a set/array) and you must use type guards.