Vyhledávání na webu

reactjs - React TypeScript - Proč se Boolean() chová jinak než dvojitý NOT (!!) operátor při pokusu o podmíněné renderování s operátorem &&?


Když pracuji s JavaScriptem, vždy jsem předpokládal, že dvojitý operátor NOT (!!) se chová stejně jako Boolean() při pokusu získat z výrazu hodnotu true/false; nicméně od té doby, co pracuji s TypeScriptem, jsem nedávno narazil na scénář, kde se chovaly odlišně, a snažím se pochopit, proč tomu tak je. Vezměme si například následující kód:

import React from 'react'

interface Props {
    myNumber: number | null
}

const Test: React.FC<Props> = ({ myNumber }) => {
    return (
        <>
            {/* Example 1 */}
            {!!myNumber && <span>{myNumber.toString()}</span>}

            {/* Example 2 */}
            {Boolean(myNumber) && <span>{myNumber.toString()}</span>}
        </>
    )
}

export default Test

Pod příkladem č. 1 kód pracuje, jak očekávám: Pokud je vykreslen, znamená to, že myNumber prošel kontrolou !!, takže nemůže být null, a tedy myNumber.toString() nevrátí chybu.

Podle příkladu č. 2 však metoda myNumber.toString() vrátí chybu s hláškou „Objekt může být null“, i když by na tento kód mělo být dosaženo pouze tehdy, pokud Boolean(myNumber) vrátí true, a Boolean(null) by mělo vždy vracet false.

Mýlím se, když si myslím, že by se měli chovat úplně stejně? Je něco souvisejícího s překladačem TypeScript, co mi uniká? Díky!

Odpověď č. 1

Boolean je typizováno jako funkce typu BooleanConstructor.

BooleanConstructor lze dále rozložit jako <T>(value?: T | undefined) => boolean.

TypeScript při kontrole, zda hodnota může být null | undefined, nezohledňuje vnitřní fungování funkce.

// Here TypeScript can directly infer that myNumber is indeed truthy 
// by the preceeding double bang (!!) check. 
const numberStrWithDoubleBang = !!myNumber && myNumber.toString();

// Here TypeScript cannot directly infer that myNumber is indeed truthy.
// To Typescript the function is a black box that takes in a number and
// returns a boolean, it does not know how the boolean value is calculated.
const numberStrWithFunction = isTruthy(myNumber) && myNumber.toString();

// While the isTruthy function above could easily have an implementation
// that does a simple truthy check on the passed in value as follows:
const isTruthy = <T>(value?: T | undefined) => !!value;

// It could also easily have an implementation with an output with no direct 
// connection to the truthy status of the passed in value such as:
const isTruthy = <T>(value?: T | undefined) => {
    const correctedValue = value ?? 0;
    const midPoint = correctedValue / 2;

    if (Math.random() * correctedValue > midPoint) {
        return true;
    }

    return false;
};

V tuto chvíli je odvozování stavu null | undefined prostřednictvím funkce považováno za příliš složité nebo by vliv na výkon byl příliš velký.

POZNÁMKA: !!0 a Boolean(0) jsou oba false, protože 0 je nepravdivá hodnota. Pokud potřebujete získat řetězcovou reprezentaci nuly, budete muset aktualizovat své kontroly.

Související články