Description
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)