-
Notifications
You must be signed in to change notification settings - Fork 12.8k
feat(7481): Operator to ensure an expression is contextually typed by, and satisfies, some type #46827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@typescript-bot pack this |
Heya @RyanCavanaugh, I've started to run the tarball bundle task on this PR at 37dd828. You can monitor the build here. |
Let's try again @typescript-bot pack this |
Heya @RyanCavanaugh, I've started to run the tarball bundle task on this PR at 37dd828. You can monitor the build here. |
@typescript-bot pack this |
Heya @andrewbranch, I've started to run the tarball bundle task on this PR at 37dd828. You can monitor the build here. |
Hey @andrewbranch, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
37dd828
to
37d57da
Compare
@DanielRosenwasser @RyanCavanaugh Thanks for the feedback. I've added the requested changes. |
@typescript-bot pack this |
Heya @RyanCavanaugh, I've started to run the tarball bundle task on this PR at 37d57da. You can monitor the build here. |
Hey @RyanCavanaugh, I've packed this into an installable tgz. You can install it for testing by referencing it in your
and then running There is also a playground for this build and an npm module you can use via |
I'd rather we avoid further polluting JS expression space with new expression-level operators. Could we achieve this with a magic type similar to // NOTE: Follows new mechanism for defining magic types like `Uppercase<T>`
// as opposed to `ThisType<T>`
type Satisfies<T> = intrinsic;
const options = { } as Satisfies<Options>; |
I find the postfix operation nice for the “ensure this literal I wrote in the middle of some expression is assignable to const actions = {
foo: payload => {
// ...
},
bar: payload => {
// ...
},
baz: payload => {
// ...
},
one: payload => {
// ...
},
fish: payload => {
// ...
},
} satisfies Record<string, (payload: Whatever) => Promise<boolean>>; You had to do a lot of reading before finding out what each const actions: extends Record<string, (payload: Whatever) => Promise<boolean>> = {
// ...
} That does have the issue that an |
I gave a lot of examples involving |
What about jsdoc compatibility? |
Considering that this syntax is filling a similar role as a type assertion, it makes sense to me that whatever keyword is used can be positioned both as a postfix and part of declaring the type of a variable, to mirror type assertions. And, like... couldn't both positions be supported with either of these keywords? Like, all the the below examples seem equally sensible to me in reading them. Am I misunderstanding why not all of these examples could work, syntactically? const foo: satisfies Bar = { ... };
applyBar({ ... } satisfies Bar); const foo: extends Bar = { ... };
applyBar({ ... } as extends Bar); Note that I personally cast no vote about which syntax to use, as I like the sound of "satisfies", and "extends" is kinda all over the place in TypeScript already, filling a ton of different roles, which can make code a little bit slower to comprehend imo. But at the same time, being able to use |
Whatever the syntax winds up being, it would be great if it could also be used to give a contextual type to JSON imports (#37831): import data from './data.json' satisfies MyType; |
Got a question on this. Given interface Foo {
bar: 1 | 2;
}
const value = { bar: 1 as const } satisfies Foo; What is the type of |
{ bar: 1 } It's not a postfix to change the type, it's a postfix to validate the type. It's making sure whatever value is there has a type which, in this case, is assignable to *I'm pretty sure there's some other stuff going on with like, turning parts of the value's type into the type in |
37d57da
to
cc37e4f
Compare
It was discussed in a design meeting (#50522), but I don’t think we had a conclusion:
|
@a-tarasyuk @andrewbranch Is the team against doing something like |
Opened #51086 for |
I wonder if it was a deliberate decision to preserve the "original" type of expression for expressions that are not satisfied by the operator (in case of an error). This is different from the |
We didn't discuss what to do in error cases, oddly enough. I think keeping the expression type regardless of outcome is the most consistent/predictable behavior, even if the net behavior is maybe a little less desirable (since, presumably, you now have two errors in your program instead of one). I think there's something weird going on with the language service displaying the asserted type in the Playground. The actual type of the variable, shown in .d.ts emit, is the expression type. |
There are 3 things I can imagine us doing:
I think the original type is fine to start with. I think the error type is possibly undesirable because you lose other semantic smarts you'd get in the editor. |
Fixes #7481
Fixes #47920