Skip to content

Allow type guards to be type checkedΒ #47468

Closed
@Pzixel

Description

@Pzixel

Suggestion

Allow type guards to be type checked

πŸ” Search Terms

Type guards narrowing

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Type guards are sometimes used when TS has no knowledge what's happening here and we need some kind of believeMe to enforce some invariants we can guarantee as developers. But there are plenty of trivial cases that can be inferred by compiler itself. And I strongly believe that if it can do it it should since it helps us with human mistakes.

It can be implemented in both breaking and non-breaking manner. I do believe that breaking manner would make future more safe but since I know how people love backward compatibility even between major versions I think an infer keyword may be used to fix the gap. It could look like

const isTen = (value: number): infer value is 10 => {
    if (value === 10) {
      const result = value; // infered to be 10
      return false; // illegal: '10' is assignable to type '10'.
    }
    return true; // illegal: 'number' is not assignable to type '10'.
};

πŸ“ƒ Motivating Example

There are multiple questions with hundreds of upvotes on SO that asks for different narrowings and they all repeat a similar pattern like

// some guard function
function notEmpty<TValue>(value: TValue | null | undefined): value is TValue { // checking some invariant
  if (value === null || value === undefined) return false;
  const testDummy: TValue = value; // compiler already infered all needed information here
  return true; // but it doesn't check it in any way even if user input clearly contradicts with what it infered
}

The problem is compiler doesn't check it at all and we can always rewrite it as:

function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
  return true; // totally legal
}

or

function notEmpty<TValue>(value: TValue | null | undefined): value is TValue {
  if (value === null || value === undefined) return false;
  const testDummy: TValue = value;
  return false; // absolutely legal
}

πŸ’» Use Cases

  • all sorts of type guards will benefit from additional compiler check which is lightyears better than code review
  • special cases include all kinds of filters like const notNulls: string[] = ['foo', 'bar', null, 'zoo', null].filter(notEmpty)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions