Repository: TypeScript
Issue: `satisfies` should work with imported / referenced values
Labels: Suggestion,In Discussion

# Suggestion

Right now, `satisfies` works on values and object literals right after they're declared. However, there are use cases when `satisfies` can't be used immediately, and the value is imported, such as JSON files.

## 🔍 Search Terms

JSON, typed JSON, satisfies JSON

<!--
  💡 Did you know? TypeScript has over 2,000 open suggestions!
  🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress.
  The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests

  Replace the text below:
-->

## ✅ Viability Checklist

<!--
   Suggestions that don't meet all these criteria are very, very unlikely to be accepted.
   We always recommend reviewing the TypeScript design goals before investing time writing
   a proposal for ideas outside the scope of the project.
-->
My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

In short, I'd like to be able to do this:

```ts
import book from 'book.json'

const foo = book satisfies BookResource
```
or, alternatively:
```ts
import book from 'book.json' with { satisfies: BookResource }
```
and have it work equal to:
```ts
const book = {
  // book fields
} satisifies BookResource
```

## 📃 Motivating Example

I have this structure in my book data JSON file:

```ts
{
  "data": [
    {
      "type": "book",
      "baseCode": "394b76ce-3ad9-4c83-b21d-d5eab7962249",
      "id": "394b76ce-3ad9-4c83-b21d-d5eab7962249",
      "url": "http://github.com/donec/dapibus/duis/at.jpg",
      "originalUrl": "http://qq.com/ante/ipsum/primis.json",
      "imageUrl": "http://dummyimage.com/246x100.png/5fa2dd/ffffff",
      "retailer": "Amazon",
      "title": "Dead End Drive-In",
      "author": "Vlad Cutmore"
    },
    {
      // more of the same schema
    }
  ]
}
```
And I have a type (interface) like:
```ts
interface BookResource {
  id?: string
  type: 'book'
  baseCode: string
  imageUrl: string
  title: string
  author: string
  originalUrl: string
  retailer: string
  url: string
}
```
_(Note, in this scenario, the source data MUST be JSON.)_

I want to make sure that if anyone modifies the JSON, they get a type error. However, doing the following results in an error:
```ts
import books from 'books.json'
// ...
const bookData = books.data satisfies BookResource[] // error - "Type {...} is not assignable to BookResource"
```

Now, I wasn't sure if this should be marked as a bug or feature request, because this works:

```ts
const blah = {
  type: 'book',
  baseCode: '394b76ce-3ad9-4c83-b21d-d5eab7962249',
  id: '394b76ce-3ad9-4c83-b21d-d5eab7962249',
  url: 'http://github.com/donec/dapibus/duis/at.jpg',
  originalUrl: 'http://qq.com/ante/ipsum/primis.json',
  imageUrl: 'http://dummyimage.com/246x100.png/5fa2dd/ffffff',
  retailer: 'Amazon',
  title: 'Dead End Drive-In',
  author: 'Vlad Cutmore'
} satisfies BookResource
```

In other words, the exact same _value_ data, when applied with the `satisfies` keyword, causes an error depending on where the value is being checked, even though it's the same value.

What seems to be the case is that `satisfies` gently coerces the type (specifically to `"book"` instead of `string`) in the latter example, but fails to do so when the value is imported.

## 💻 Use Cases

<!--
  What do you want to use this for?
  What shortcomings exist with current approaches?
  What workarounds are you using in the meantime?
-->

Currently, I want to use this for JSON, but note that there are other cases where you might want to "check" and gently nudge the type at compile time the exact same way that happens with `satisfies` at assignment time.

Because, similar to the above example, this also causes an error:
```ts
const foo = {
  type: 'book',
  baseCode: '394b76ce-3ad9-4c83-b21d-d5eab7962249',
  id: '394b76ce-3ad9-4c83-b21d-d5eab7962249',
  url: 'http://github.com/donec/dapibus/duis/at.jpg',
  originalUrl: 'http://qq.com/ante/ipsum/primis.json',
  imageUrl: 'http://dummyimage.com/246x100.png/5fa2dd/ffffff',
  retailer: 'Amazon',
  title: 'Dead End Drive-In',
  author: 'Vlad Cutmore'
}
const bar = foo satisfies BookResource
```
In TypeScript / JavaScript terms, these should be equivalent statements, and TypeScript should be able to
1. say that the value of `foo` satisfies the type of `BookResource`
2. coerce `bar` to be of `type: "book"` vs `type: string`, just as it would if `satisfies` immediately followed the value.

**1st note:** obviously I could just use `as BookResource` instead of `satisfies BookResource`, but of course that bypasses the type-checker entirely, and defeats the purpose. Then, the JSON could have any data / shape whatsoever, with no errors provided.

**2nd note:** I can also sorta get there with `satisfies Array<Omit<BookResource, 'type'> & { type: string }>` but that's kind of gross, and I want to enforce that the type truly is "book" and not just a string. JSON type inference is helpful but it isn't perfect, and currently there's no way to actual tell it how to interpret string literal types.