0

I think I'm missing something basic on how you can check for a truthy value with && in Typescript.

Why can props.function still be undefined in test1 and has to be checked like I did in test2.

import React from "react";

interface PropsModel {
    label?: string
    function?: Function,
}

function test1(props: PropsModel) {
    return (
        <div>
            {props.label && <p>{props.label}</p>} // props.label is checked for undefined
            {props.function && <button onClick={() => props.function()}>Dummy button</button>} // props.function is not checked for undefined
        </div>
    )
}

function test2(props: PropsModel) {
    return (
        <div>
            {props.label && <p>{props.label}</p>} // props.label is checked for undefined
            {props.function && <button onClick={() => {if (props.function) props.function()}}>Dummy button</button>} // props.function is checked for undefined
        </div>
    )
}

EDIT 1: Added Link to playground

Link to Typescript playground

Sean A.S. Mengis
  • 129
  • 2
  • 13

2 Answers2

3

I am by no means an expert on this matter of TS as I too have wondered this. My assumption so far is to do with the level of "scope". Aka the onClick function is of a different scope to your Component. If you're 100% sure that the function will exist within the OnClick you can do either of the below.

import React from "react";

export type Function = () => void;

export type Input = {
    label?: string;
    function?: Function;
}

function test1(props: Input) {
    return (
        <div>
            {props.label && <p>{props.label}</p>} // props.label is checked for undefined
            {props.function && <button onClick={() => (props.function as Function)()}>Dummy button</button>} // props.function is not checked for undefined
        </div>
    )
}

or simply

import React from "react";

interface PropsModel {
    label?: string
    function?: Function,
}

function test1(props: PropsModel) {
    return (
        <div>
            {props.label && <p>{props.label}</p>} // props.label is checked for undefined
            {props.function && <button onClick={() => props.function!()}>Dummy button</button>} // props.function is not checked for undefined
        </div>
    )
}

A ! has been added to the {props.function && <button onClick={() => props.function!()}>Dummy button</button>} line here. ! simply tells TS that you are 100% sure that the optional type will definitely exist at this point.

LoveDev
  • 257
  • 1
  • 9
  • Didn't know that "!" existed. Good to know, thanks! The scope hypothesis could be correct. I'll wait to see if somebody else can confirm that and I'll accept your answer. – Sean A.S. Mengis Sep 24 '21 at 11:34
0

Your function property is optional. hence to use such property we must use optional chaining.

What you need to do is

function test1(props: PropsModel) {
    return (
        <div>
            {props.label && <p>{props.label}</p>}
            {props.function && <button onClick={() => props.function?.()}>Dummy button</button>} // props.function is checked for undefined then it will be called
        </div>
    )
}

Note that to use optional chaining your typescript version must be typescript >= 3.7