Skip to content
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

Get rid of tsd #436

Merged
merged 3 commits into from
Dec 7, 2023
Merged

Get rid of tsd #436

merged 3 commits into from
Dec 7, 2023

Conversation

markw65
Copy link

@markw65 markw65 commented Sep 8, 2023

Get rid of tsd by rewriting expectType in a way that lets vanilla typescript check the types with the same precision.

Comment on lines +18 to +26
function expectExact<T>() {
return function<U extends T>(
tValue: U
): [T] extends [U] ? () => U : ["Argument of type", U, "does not match", T] {
// @ts-expect-error Just for type checking
return () => tValue;
};
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the one hand, I was inclined to keep the expectType name, but on the other, that would cause confusion for people familiar with tsd. But we could go either way.

We could also break this into two functions, which might make it easier to spot that you accidentally omitted the trailing ():

function exact<T>() {
   return function<U extends T>(
     tValue: U
   ): [T] extends [U] ? () => U : [U, "does not match", T] {
     // @ts-expect-error Just for type checking
     return () => tValue;
   };
 }
function check<T>(fn: ()=>T): void {
  fn();
}

And then call check(exact<T>()(arg)).

In fact, this makes the error message work better. Now its:

Argument of type '[string, "does not match", string | number]' is not assignable to parameter of type '() => unknown'.
  Type '[string, "does not match", string | number]' provides no match for the signature '(): unknown'.

@hildjj
Copy link
Contributor

hildjj commented Dec 3, 2023

This one is next after #430

@hildjj
Copy link
Contributor

hildjj commented Dec 6, 2023

Rebase and changelog, please.

@hildjj hildjj merged commit 274cd48 into peggyjs:main Dec 7, 2023
9 checks passed
@markw65
Copy link
Author

markw65 commented Dec 7, 2023

Updated. I'll just note one other way to do this that might be a bit clearer.
See typescript playground

Basically, instead of exactType()(x)(), we could use subtypeOf<T>()(x).is_exact. It's the same trick, but (in my opinion) it reads a bit better. Without the is_exact, it just checks for any subtype; with the is_exact it checks for exact types (the original exactType does the same if you omit the final () - but its less clear to readers what the () is there for)

@hildjj
Copy link
Contributor

hildjj commented Dec 7, 2023

I don't have a strong opinion, so I'll defer to your taste. Feel free to send another PR if you decide you like another way better.

@reverofevil
Copy link

Well, either trick is using heavily unstable features of TypeScript.

I wouldn't recommend either approach for future rewrites, but for a small localized change to remove tsd this is already good.

@markw65 markw65 deleted the kill-tsd branch December 7, 2023 20:12
@markw65
Copy link
Author

markw65 commented Dec 7, 2023

Well, either trick is using heavily unstable features of TypeScript

I checked it back to ts-3.3.3. Same behavior everywhere - so absent some statement of intent to change the behavior (perhaps you've seen something?) I think it's pretty stable. Its just currying; its hard to see how it could break without breaking huge amounts of typescript...

@reverofevil
Copy link

reverofevil commented Dec 7, 2023

Sorry, I didn't mean the problem is with currying. Problem is with conditional types, and, more precisely, them lacking any foundation in type theory. They might look like they're working, but even that equality check is incorrect. There're "better" type equalities in TS, but no single correct one. Unfortunately even type equality in TS is still an open problem.

Mapped object types, conditional types, indexed types, type guards and, well, majority of TS's type system is unsound and inconsistent. It's best to avoid any of that if reliability is at stake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants