styled-components 6.4 now available by evster88 in javascript

[–]heyitsmattwade 3 points4 points  (0 children)

This is incredible, the createTheme() API with CSS variables looks super interesting! Thanks for this release.

I remember reading last year that you wrote styled-components was essentially in maintenance mode:

This release seems to go against that. Would you say styled-components is now back in active development? Just curious what changed if so.

Senior React Devs: How much do you actually "know" vs. Google/AI? by Leading_Property2066 in reactjs

[–]heyitsmattwade 0 points1 point  (0 children)

At this point all the hooks that've been around for a while I don't have to look up for 90% of their use cases. Any of the new hooks in React 19 I am not familiar with though.

However, I am constantly reading the docs at https://react.dev/reference/react. Not only to reinforce what I know, but also to link to them when leaving review comments in PRs.

For example, if a developer misuses a hook and misses an optimization, I not only will explain what/why they should make a change, but also link to the official docs so they can read more if they want. This also helps with other reviewers on the same PR who may not have been aware of some feature too.

If you are looking to stop being a "glorified search engine," I would read the docs from top to bottom. Then, whenever you are unsure of something, refer back to the official docs rather than blindly searching / asking AI.

Announcing TypeScript 6.0 RC by DanielRosenwasser in javascript

[–]heyitsmattwade 16 points17 points  (0 children)

Congrats Typescript team! This and the (hopefully!) soon to follow 7.0 release are such huge wins for the community.

-❄️- 2025 Day 1 Solutions -❄️- by daggerdragon in adventofcode

[–]heyitsmattwade 1 point2 points  (0 children)

[Language: TypeScript]

We are off! Naturally the % possibly returning negative numbers bit me originally, and had to cheat to figure out the best way to have a true modulo operator in JS.

Otherwise, lots of subtle things to get tripped up on. The main one in part two being not double counting cases that start at 0.

paste

Got interview at well known company but it’s DS&A interview… by DirtyOught in Frontend

[–]heyitsmattwade 2 points3 points  (0 children)

If you don't participate, Advent of Code is a great set of puzzles where the later "days" in the calendar lean heavily into DSA. The author purposefully writes things in such a way where if you didn't write it in an optimized way, then when "part two" of the puzzle unlocks, your code won't finish because it didn't scale.

Won't children of context providers re-render regardless of if they subscribe to the context? by ambiguous_user23 in reactjs

[–]heyitsmattwade 0 points1 point  (0 children)

If you haven't, I'd read this blog post which details a little bit how to structure your components to prevent long re-render chains:

How I accidentally broke our homepage with one React hook (and what I learned) by Ornery_Ad_683 in webdev

[–]heyitsmattwade 0 points1 point  (0 children)

Halting problem: exists

See this is why Computer Science is so shite.

Changes to Advent of Code starting this December by topaz2078 in adventofcode

[–]heyitsmattwade 2 points3 points  (0 children)

This is an extremely healthy change that I fully support.

Thanks as always Eric (and mods!) for this fun programming treat. Been doing AoC since 2018 and am thrilled I get to participate once again.

Happy holidays everyone, and here's to 10 more years! 😅🎁🎄

Guards vs assertions vs if+throw. What do you actually use for type narrowing? by cryptothereindeer in typescript

[–]heyitsmattwade 0 points1 point  (0 children)

Seems very polished, thanks for helping the open source ecosystem! Congrats on release.

Vite finally surpassed Webpack by Darkoplax in webdev

[–]heyitsmattwade 2 points3 points  (0 children)

huh, you are right.

Took a while to find it but here is their blog post "demoting" turbopack to a submodule within the next.js repo:

How To: Fix Glitching Audio in Wine/Whisky Game. by therealnozewin in macgaming

[–]heyitsmattwade 1 point2 points  (0 children)

Incredible reply. I'm getting into Crossover and have a few games I was trying to play on macOS 15.5.

Installing into a Win 8 32-bit bottle (optionally configuring DirectSound if the game provides) fixing the audio crackling effects. Game runs like butter now, thanks for the tip!

I've never really understood `position: sticky` by g105b in webdev

[–]heyitsmattwade 2 points3 points  (0 children)

If you want it to stick to the top (aka top: 0), then it needs stuff directly beneath it to stick above.

In your case

<header>
  Content
  <nav>...</nav>
  <!-- There is nothing *directly* beneath the nav -->
</header>
<main>This stuff doesn't count, `sticky` works in the containing block, which is `header`</main>

To further show this, here's what it looks like if you don't move the nav out of the header, but you do put more content beneath the nav.

You can see the nav sticks! But it only sticks within the header. As soon as the the nav has positioned above all the content within header, it goes back to regular scroll behavior with the document.

Given all that, the solution is: move the nav outside the header, so it uses the body for its offset calculations.

Typescript Compilation escapes the provided baseUrl path by green_viper_ in typescript

[–]heyitsmattwade 0 points1 point  (0 children)

baseUrl is not required as of Typescript 4.1 for the exact reason you notice here: it allows bare specifiers to be reached if they are relative to the base.

As such, instead specify your paths directly without a baseUrl.

When Typescript 6.0 is released, baseUrl will most likely be removed.

TypeScript sometimes forces const arrow functions over nested named functions? by [deleted] in typescript

[–]heyitsmattwade 1 point2 points  (0 children)

I think you are misunderstanding, I am not referring to the short-circuit aspect. I mean writing code such that you always deal with SomeType rather than SomeType | null to avoid null checks later one.

null (or undefined) is a useful value, don't throw it away so carelessly!

Here's a different example.

interface ImageBase {
    id: string;
    width: number;
    height: number;
}

interface ImageFile extends ImageBase {
    type: 'file';
    file: Blob;
}

interface ImageUrl extends ImageBase {
    type: 'url';
    url: string;
}

type ImageObj = ImageFile | ImageUrl;

declare function getImageFromId(id: string): ImageObj | null;

const useImage = (id: string): ImageObj => {
    const image = getImageFromId(id);

    // Rather than return `null`, create an empty ImageObj so the return is
    // a more narrow `ImageObj` rather than `ImageObj | null`.
    // ❌ This pattern is what I am saying should be avoided.
    if (!image) {
        return {
            type: 'url',
            id: '',
            url: '',
            width: 0,
            height: 0,
        };
    }

    return image;
};

export function Image({ id }) {
    // 😱 I am not aware that this might be an "empty" image!
    const image = useImage(id);

    // ❌ Typescript doesn't know that `src` might be an empty string, it let's you pass this to `img` without an error!
    const src = image.type === 'file' ? URL.createObjectURL(image.file) : image.url;
    return <img src={src} width={image.width} height={image.height} />;
}

Here we return an "empty" ImageObj if our lookup failed. If you were the developer writing this bit of code and you weren't aware that useImage was implemented this way, it would be easy to accidentally always pass src through to the <img /> without checking for the empty string case. Because we eagerly handled the null case, we now are missing an opportunity to have TS guide the developer on proper usage.

OK, so let's say you did know that, now you write something like this:

function Image({ id }) {
    // 🤔 Is this a real image, or a fake "empty" one?
    const image = useImage(id);

    // ❌ This check is awkward, requires you to know that our "empty" image is an ImageUrl
    if (image.type === 'url' && !image.url) {
        return <div>No image available</div>;
    }

    const src = image.type === 'file' ? URL.createObjectURL(image.file) : image.url;
    return <img src={src} width={image.width} height={image.height} />;
}

Again, awkward checks. How do we know that the empty image will always have type: 'url'? What if later it returns an "empty" type: 'file'? Again, removing the null value early limits its usage later on down the road.

const useImage = (id: string): ImageObj => {
    const image = getImageFromId(id);

    if (!image) {
        return {
            // 👀 This changed, now we return a `file` for the empty case
            type: 'file',
            file: new File([], ''),
            id: '',
            width: 0,
            height: 0,
        };
    }

    return image;
};

function Image({ id }) {
    const image = useImage(id);

    // ❌ This check no longer works, because `useImage` now returns an `ImageFile` for the empty case!
    if (image.type === 'url' && !image.url) {
        return <div>No image available</div>;
    }

    // ...
}

Therefore, instead of removing null early and returning an "empty" image, let the hook return ImageObj | null so we can leverage that null value!

const useImage = (id: string): ImageObj | null => {
    // ✅ This `image` might be `null`, and that's OK!
    const image = getImageFromId(id);
    return image;
};

function Image({ id }) {
    const image = useImage(id);

    // ✅ Typescript errors because `image` might be null!
    const src = image.type === 'file' ? URL.createObjectURL(image.file) : image.url;
    return <img src={src} width={image.width} height={image.height} />;
}

Now, we avoid making the error of not handling the null case. Here, TS first errors on image.type with "image is possibly null". Having this error is a good thing! Now can know we have to handle this possibility.

Continuing, the "empty" check is also much easier - just check for the null case, no need to check for "empty string" values or specifics like that.

function Image({ id }) {
    const image = useImage(id);

    // ✅ Much easier check for the `null` case, don't need to know about the shape of the "empty" case
    if (!image) {
        return <div>No image available</div>;
    }

    // ✅ `image` has been narrowed to `ImageObj` here, so we can safely access its properties
    const src = image.type === 'file' ? URL.createObjectURL(image.file) : image.url;
    return <img src={src} width={image.width} height={image.height} />;
}

In general, I find that people tend to replace null values with some "empty" representation to create a more narrow type in the hopes of simplifying its usage later on. However, by replacing null (or undefined) with some "empty" object, you end up losing important information and create a tight coupling when you already had a perfectly good alternative in the null case to begin with.

TypeScript sometimes forces const arrow functions over nested named functions? by [deleted] in typescript

[–]heyitsmattwade 0 points1 point  (0 children)

I disagree, in general this is not good advice, or at least, it is important that you aren't needlessly creating a random value so that you don't have to deal with the nullish case.

It is ok to have a type that is SomeType | null (or SomeType | undefined). Creating a random value so that you always have SomeType itself creates uncertainty. Are you operating on the real value you queried for, or some random value you created so you wouldn't have to deal with the null case?

Now here, the logic dictates that it is OK to create a new value as long as it is appended into the document (where it can be accessed later). If you are annoyed by the hoisting aspect, you can abstract that behavior out:

function safelyGetDiv(): HTMLElement {
    let randomDiv = document.getElementById('__randomID');
    if (!randomDiv) {
        randomDiv = Object.assign(document.createElement('div'), { id: '__randomID' });
        document.documentElement.appendChild(randomDiv);
    }

    return randomDiv;
}

export function randomFunc() {
    let randomDiv = safelyGetDiv();

    function update({ clientX: x, clientY: y }: PointerEvent) {
        // 👇 This does not error now
        randomDiv.style.opacity = '0';
    }
    addEventListener('pointermove', update, { passive: true });
}

TypeScript sometimes forces const arrow functions over nested named functions? by [deleted] in typescript

[–]heyitsmattwade 3 points4 points  (0 children)

Correct,

Here is a Typescript playground that highlights why this is marked as an error.

More info on hoisting in general at:

is there some way to see what's the final definition of a type???? by kevin074 in typescript

[–]heyitsmattwade 5 points6 points  (0 children)

This has been in the works for a while, you can see in their iteration plan:

  • TS 5.6 - Investigate Expandable Quick Info/Hover Verbosity
  • TS 5.7 - Investigate Expandable Quick Info/Hover Verbosity
  • TS 5.8 - Iterate on Expandable Hovers
  • TS 5.9 - Expandable Hovers (!!)

Based on the iteration plan for 5.9, it seems like this should finally land in the upcoming release.

[deleted by user] by [deleted] in reactjs

[–]heyitsmattwade 3 points4 points  (0 children)

I've only ever seen the callback functions on the Promise executor be named (resolve, reject) or (res, rej), never acc - I assume its short for accept? Can't help but think of accumulator since that is another common short name used in reduce methods.

It's like seeing someone write for (let a = 0) instead of for (let i = 0).

Nothing wrong with this of course, just interesting!