Typescript: Allow undeclared properties, assume undefined

Viewed 43

Consider the following code example:

declare const isDisabled: {reason: string} | false;
const disabledReason: string = isDisabled?.reason || '';

The the JavaScript code is perfectly valid and it works in runtime, but with typescript you get this error: "Property 'reason' does not exist on type 'false | { reason: string; }'"

Is there a way to make typescript allow this but interpret "reason" as undefined for the case that the property doesn't exist? (Which is the runtime behavior of JavaScript). I expect the resolved type to be string | undefined, and the compilation to pass.

3 Answers

Your code fails for two reasons:

  1. Because you assign false in the statement above, typescript infers that isDisabled is always false. If you hover isDisabled in the second statement you will see isDisabled: false.

  2. isDisabled?.reason doesn't specify that reason exists on the object, you first have to cancel out the possibility of it being false by using:

const disabledReason: string = isDisabled ? isDisabled?.reason : '';

And in complete: (function used because typescript will always infer that isDisabled === false otherwise)

const isDisabled: {reason: string} | false = false;
const isDisabledWithReason: {reason: string} | false = { reason: 'Aborted' };

function getDisabledReason(a_isDisabled: {reason: string} | false): string {
  return a_isDisabled != false ? a_isDisabled.reason : '';
}

console.log(getDisabledReason(isDisabled)); // ""
console.log(getDisabledReason(isDisabledWithReason)); // "Aborted"

Just be a little more verbose:

const disabledReason: string = isDisabled ? isDisabled.reason : '';

Posting my own answer to summarize previous comments.

The first thing to understand is that I assumed isDisabled?.reason is identical to isDisabled && isDisabled.reason but apparently this is not the case, as as @kaya3 pointed out, the optional chaining operators works only for undefined / null values.

So there are two possible solutions here:

  1. Adding an explicit condition for the truthiness of isDisabled:
isDisabled && isDisabled.reason
  1. Changing "false" to "null"
declare const isDisabled: {reason: string} | null;
const disabledReason: string = isDisabled?.reason || '';

What I initially wanted was for typescript to enable something like that:

const x = false.reason; // inferred value is undefined

But seems like this is not possible and unadvised.

Related