It seems to me that TypeScript interprets typeof x === 'string' not only as a simple boolean, but as some kind of a boolean is string type.
Consider this example:
const tryInference = function(maybeStr?: string): void {
const isStrI = typeof maybeStr === 'string'; // inferred type "is string"
const isStrB: boolean = typeof maybeStr === 'string'; // explicit boolean
console.log( isStrI && maybeStr.charAt(0) ); // <-- ok
console.log( isStrB && maybeStr.charAt(0) ); // <-- TS18048: 'maybeStr' is possibly 'undefined'.
const indeedStr1: string = isStrI ? maybeStr : ''; // <-- ok
const indeedStr2: string = isStrB ? maybeStr : ''; // <-- TS2322: Type 'string | undefined' is not assignable to type 'string'
console.log( indeedStr1, indeedStr2 );
};
I understand that in case of isStrI TypeScript knows that if typeof maybeStr === 'string' then maybeStr.charAt is available.
I suppose that in case of isStrB && maybeStr.charAt(0) TypeScript interprets it as true && maybeStr.charAt(0), and doesn’t have the relation to the typeof maybeStr === 'string' anymore ? (if isStrB is true, of course)
That makes me wonder:
-
Can I annotate
isStrIexplicitly somehow, without destroying the information thatmaybeStris of typestring? -
Am I right with my assumptions ? Does somebody have a more detailed explaination ?
>Solution :
This isn’t currently possible.
The support for control flow analysis of aliased conditions as implemented in microsoft/TypeScript#44730 doesn’t occur at the type level in a way you can manipulate programmatically. The type of the variable is just boolean either way; no type annotation could capture its relationship to maybeStr (type predicates do not exist as standalone types). And furthermore, annotating the variable destroys the relationship:
Narrowing through indirect references occurs only when the conditional expression or discriminant property access is declared in a
constvariable declaration with no type annotation [emphasis added], and the reference being narrowed is aconstvariable, areadonlyproperty, or a parameter for which there are no assignments in the function body.