question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using `satisfies` on a self-referencing object causes `any` - TS 4.9.2-RC

See original GitHub issue

Bug Report

🔎 Search Terms

🕗 Version & Regression Information

Version 4.9.2-rc

💻 Code

interface Items {
  id: 'a' | 'b';
  condition: () => boolean;
}

// 'items' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts (7022)
const items = {
  foo: {
    id: 'a',
    condition: () => true
  },
  bar: {
    id: 'b',
    condition: () => items.foo.id === 'a'
  },
} satisfies Record<string, Items>;

🙁 Actual behavior

items implicitly has type any.

🙂 Expected behavior

items should be checked with the Items interface and still have typesafe keys.

Issue Analytics

  • State:open
  • Created 10 months ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
fatcerberuscommented, Nov 12, 2022

I feel like TS needs better error messages.

The error text…

because it does not have a type annotation and is referenced directly or indirectly in its own initializer

…implies that simply referencing yourself is sufficient cause for error, but in reality sometimes it’s allowed (intentionally, even). I’m starting to see why people complain so much about TS being inconsistent—context matters, but the error messages tend to speak in absolutes, making any difference in error-producing behavior look like a bug…

I guess if I had to put my finger on it, it’s the difference between “you’re not allowed to do this” vs. “I can’t resolve this and here’s the complication I ran into while trying”, and it’s easy to read some errors as implying the former when it’s really the latter.

1reaction
DanielRosenwassercommented, Nov 12, 2022

I’m not sure if there’s a way for us to avoid pulling on the type of types here before it’s been initialized, but since you can observe the same thing with a “fake” version of satisfies in older versions of TypeScript, I might be tempted to say that this is an expected design limitation.

interface Items {
  id: 'a' | 'b';
  condition: () => boolean;
}

declare function satisfies<U, T extends U = U>(val: T): T

// 'items' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.ts (7022)
const items = satisfies<Record<string, Items>>({
  foo: {
    id: 'a',
    condition: () => true
  },
  bar: {
    id: 'b',
    condition: () => items.foo.id === 'a'
  },
});

That said, maybe we could do something a little different here. We could possibly defer all comparisons for satisifes until after all deferred function bodies have been checked as well. So basically satisfies does nothing except for provide a contextual type at first, and then is checked after everything else.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Documentation - TypeScript 4.9
JavaScript's in operator can check whether a property exists on an object. Previously, TypeScript allowed us to narrow away any types that don't...
Read more >
Self-referencing a mapped type in TypeScript - Stack Overflow
I'm open to changing the source Lang<T> type, as long as it still allows me to express node types and fold / reduce...
Read more >
Self referencing object literal in JavaScript - clubmate.fi
Sometimes it is desirable to allow access to a property that returns a dynamically computed value, or you may want to reflect the...
Read more >
Ungrounded Self-Reference: The Solution to the Liar Paradox?
self -reference can also satisfy criterion 1 by defusing all forms of the Liar. Paradox. In §6 I argue that ungrounded self-reference satisfies...
Read more >
Self-Reference - Stanford Encyclopedia of Philosophy
The philosophical interest in self-reference is to a large extent centered ... \(Q(y)\) is the universal predicate true of any object.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found