Open bgenia opened 1 year ago
This was discussed a bit at #47920. Your example is missing what I'd consider the most straightforward solution:
const f: () => Promise<Foo> = async () => ({ a: 1 })
This was discussed a bit at #47920. Your example is missing what I'd consider the most straightforward solution:
const f: () => Promise<Foo> = async () => ({ a: 1 })
This has the same problem as my 1st example, you have to retype generics
Here's a more complex example to show why it's inconvenient:
type Foo<T> = { foo: T }
type Bar<T> = { bar: T }
declare function makeFoo<T>(value: T): Foo<T>
declare function makeBar<T>(value: T): Bar<T>
type Value = { value: number }
const f = async () => makeFoo(makeBar({ value: 1 }))
Now I have to type 3 generics:
const f: () => Promise<Foo<Bar<Value>>> = async () => makeFoo(makeBar({ value: 1 }))
you have to retype generics
This only applies to Promise
, though. In all other cases, you're writing the full type again.
you have to retype generics
This only applies to
Promise
, though. In all other cases, you're writing the full type again.
I used promises because it's the most obvious example, but you can have all kinds of functions that take your value and wrap it in different generics. I updated my example to demonstrate this.
The most painful thing this would remedy is cases such as #9998, which forces you to do true as boolean
. I believe there are "best practices" these days that force you to do x satisfies T as T
—based on feature requests we've closed in ts-eslint.
We would find this feature very useful since by using playwright, we create mocks for our application and we are using satisfies
to ensure that the mock is correct for the given type. however we also have to use as
to provide better intellisense in vscode for the given mock resulting in many satisfies T as T
where T may be a very long string since we use types generated by grpc.
I was about to create a feature request, but I think this is asking for the same thing. Basically, I just want something like
X satisfies as T
to be syntactic sugar for X satisfies T as T
. As mentioned by @Josh-Cena and @raythurnevoid, this seems to be a common and sometimes verbose pattern. Just some simple syntactic sugar to remove the duplication of T
would be fantastic.
Also, just to link it, this feature would pretty much address: https://github.com/microsoft/TypeScript/issues/13626
🔍 Search Terms
as, satisfies, type assertion, type casting
✅ Viability Checklist
⭐ Suggestion
I suggest adding a safe type assertion operator, a kind of middle ground between current
as
andsatisfies
.as
, it should cast the expression to the asserted typesatisfies
, it should only allow assertion if the asserted type is wider than the expression typeHere's what it might look like:
📃 Motivating Example
For example, such operator will allow to safely give named types to expressions without declaring extra variables or helper functions.
Consider an async function
f
that returns an object of typeFoo
:I want the returned object to strictly be of
Foo
type, how do I enforce this?1) Hard code the return type
The problem here is that I must write
Promise<Foo>
instead of justFoo
, but thePromise
part can be inferred just fine. In real world these generics can be arbitrarily complex.2) Declare a variable
This is better than retyping generics but still pretty verbose.
3) Use a helper function
This is ok but still requires writing/importing helper functions.
as
is not an option here because it's unsafe,satisfies
is neither because it doesn't name the type. Naming a type can be important for documentation purposes, this proposal allows to do this with less boilerplate.💻 Use Cases
As described above, this feature can be used to safely cast expressions to specified types. A practical example when it can be useful is naming a type in an expression. Currently this is only covered by custom helper functions such as
<T>(value: T): T => value
.