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.
