1

This question was split from questions/72839100 per @jcalz's comment.

In the following snippet,

declare const foo: Record<string, string>;
declare function bar(foo: Record<string, string>): asserts foo is {};
bar(foo);
   foo;
// ^?

foo is {} (so foo.prop yields an error) but in

declare const foo: Record<string, string>;
declare function bar<T>(foo: T): asserts foo is T & {};
bar(foo);
   foo;
// ^?

foo is Record<string, string> (thus foo.prop works).

Is it working as intended that the type inference of foo is different in these two cases due to the presence of intersection in type predicate, because Record<string, string> & {} resolves to {}, as in the question mentioned above? Why TypeScript doesn't do a intersection internally, such that a manual intersection becomes necessary?

graphemecluster
  • 301
  • 1
  • 9
  • Checked your second example, inside `if()` condition foo is `{}` (empty type) too. I think a lot of confusion is caused by mixing two cases of `foo` - first one as constant variable, second one is function param. – raina77ow Jul 04 '22 at 08:48
  • `foo is typeof foo & {}` collapses to `foo is unknown & {}` and thus `foo is {}`. You have shadowed the outer `foo` with the function parameter. If you change that then things behave differently; see [here](https://tsplay.dev/NlEoGm). So what are you asking about here? Variable shadowing? Intersections of `unknown` with `{}`? Intersections of `Record` with `{}`? Something else? Please consider [edit]ing the question to clarify. – jcalz Jul 04 '22 at 13:59
  • @jcalz Thanks for pointing that out. I've edited the question according to [this tweet](https://twitter.com/uhyo_/status/1543908224096935941) to prevent misunderstanding. – graphemecluster Jul 05 '22 at 10:21
  • @raina77ow I meant to be the type of the former one. I've edited the question to reflect this. – graphemecluster Jul 05 '22 at 10:23
  • 1
    Could you edit so as not to shadow variable names? There's no reason why the function parameter needs to be the same name as the variable you pass in, and it's just confusing. Like, [this version](https://tsplay.dev/w1P98W) is the same as yours except that there's no shadowing going on. – jcalz Jul 05 '22 at 11:45
  • Note that `Record & {}` resolves to `Record` and not `{}`, so it seems like there's a faulty premise in the question. I don't see the type predicate being relevant at all. Could you clarify and elaborate about the issue you're facing? The more I look at this question the more confused I get. – jcalz Jul 05 '22 at 11:47
  • @jcalz the two snippet are completely independent. Let's stop the game. My question is, 1. if `Record & {}` resolves to `Record`, why the first snippet resolves `foo` to `{}` instead of `Record`? 2. In general, is writing a type predicate with `typeof arg & ...` practical? – graphemecluster Jul 06 '22 at 14:26
  • For Q2., I mean, isn't it TypeScript's job to do the intersection? P.S. I rewrote the `bar` function of the second snippet. – graphemecluster Jul 06 '22 at 15:15
  • Type predicates do not always result in an intersection. If you have `function f(x: X): asserts x is Y` then you might get `X & Y` or you might get something like `Extract` or `Extract`, depending on how "related" the compiler sees `X` and `Y`. – jcalz Jul 06 '22 at 20:14
  • As an authoritative-ish answer I'd point to [this comment](https://github.com/microsoft/TypeScript/issues/47283) in a GitHub issue about type predicate narrowing. If you want me to write that up as an answer, with explanations, I'd be happy to do so. Otherwise, what am I missing? (And please know that I am communicating in good faith. When you say "lets stop the game" it sounds like you assume I am *intentionally* misunderstanding or digressing. Please be assured that I'm instead trying to understand and clarify the question so that any answer I give will be applicable.) – jcalz Jul 06 '22 at 20:20
  • @jcalz Thank you. That's exactly what I've been looking for. I would definitely appreciate if you put it into an answer. And last but not least, thank you for your patience with me. – graphemecluster Jul 07 '22 at 20:13
  • Okay, I'll write up an answer to this when I get a chance. It might not be until tomorrow. – jcalz Jul 07 '22 at 23:40

0 Answers0