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

fix(types): Mark more methods bivariant #1029

Merged
merged 4 commits into from
Jul 16, 2022
Merged

Conversation

RyanCavanaugh
Copy link
Contributor

Fixes some upcoming build breaks in TypeScript 4.8. I'm not entirely sure the true root cause, but it looks like we're computing the correct variance of more of these types, leading to a (correct) error issued in covariant use sites like this:

export function useStore<TState extends State, StateSlice>(
  api: WithReact<StoreApi<TState>>, // <- correctly marked as constraint violation

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jun 23, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 32d7998:

Sandbox Source
React Configuration
React Typescript Configuration
React Browserify Configuration
React Snowpack Configuration
React Parcel Configuration
Next.js Configuration

@dai-shi
Copy link
Member

dai-shi commented Jun 23, 2022

@devanshj what's your call?

Co-authored-by: Daishi Kato <dai-shi@users.noreply.github.com>
@RyanCavanaugh
Copy link
Contributor Author

Here's a minimal version of what changed in 4.8:

type Action<T> = (state: T) => T;
export type MakeBivariantMethod<T> = {
  signature(arg: T | Partial<T> | Action<T>): void;
}['signature']
export interface StoreApi<T> {
  prop: MakeBivariantMethod<T>;
}
type CheckExtendsStoreApi<T extends StoreApi<unknown>> = T;
type Test<T> = CheckExtendsStoreApi<StoreApi<T>>; // <- New correct error

@devanshj
Copy link
Contributor

devanshj commented Jun 24, 2022

It seems to me that in 4.8.0-dev.20220613 the following code was compiling and hence #1004 was a good fix...

export interface StoreApi<out T> {
  getState: () => T
  setState(state: T | Partial<T> | ((state: T) => T)): void
}

But now in 4.8.0-dev.20220624 the above code does not compile which is correct and consistent with the change you mention here.

So now this fix (ie #1029) is a more correct one (I think @Andarist also reduced it to this but I wasn't sure then because #1008 was compiling). Although you don't need nor should you make subscribe bivariant because it's already covariant and has no contravariance contribution to StoreApi<T> so that can be left as it is. The only change needed is this...

- ((state: T) => T)
+ { _(state: T): T }["_"]

I think in that case we don't even need downlevel-dts. I can make changes to #1004 or we can proceed with #1029 whatever @dai-shi prefers.

but it looks like we're computing the correct variance of more of these types

I'm not sure what "correct" means here. If by correct we mean mathematical correctness then we don't a way to measure correctness as bivariance is already mathematically incorrect (ie interface F<out T> { _(t: T): void } compiles), so correct is whatever we decide to be correct by deciding how much unsoundness we want to allow.

Also the change is a bit weird...

interface F<out T> { // compiles
  _(t: T): void
}

interface G<out T> { // compiles
  _(t: (t: T) => T): void
}

interface H<out T> { // compiles
  a(t: T): void
  b(t: ((t: T) => T)): void
}

interface I<out T> { // does not compile
  _(t: T | ((t: T) => T)): void
}

I'd expect I to also compile if F, G & H compile. I think this is violating a lot more mathematics than necessary imo. Looks like a bug to me.

src/vanilla.ts Outdated
Comment on lines 16 to 24
export type SetState<T extends State> = {
_(
partial: T | Partial<T> | ((state: T) => T | Partial<T>),
partial: T | Partial<T> | BivariantStateComputer<T>,
replace?: boolean | undefined
): void
}['_']
type BivariantStateComputer<T> = {
_(state: T): T | Partial<T>
}['_']
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's inline BivariantStateComputer.

Suggested change
export type SetState<T extends State> = {
_(
partial: T | Partial<T> | ((state: T) => T | Partial<T>),
partial: T | Partial<T> | BivariantStateComputer<T>,
replace?: boolean | undefined
): void
}['_']
type BivariantStateComputer<T> = {
_(state: T): T | Partial<T>
}['_']
export type SetState<T extends State> = {
_(
partial: T | Partial<T> | { _(state: T): T | Partial<T> }["_"],
replace?: boolean | undefined
): void
}['_']

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, inlining seems simple enough and more consistent.

Co-authored-by: Devansh Jethmalani <jethmalani.devansh@gmail.com>
Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

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

well, i'm not a ts wizard, but it looks good.

src/vanilla.ts Outdated
Comment on lines 16 to 24
export type SetState<T extends State> = {
_(
partial: T | Partial<T> | ((state: T) => T | Partial<T>),
partial: T | Partial<T> | BivariantStateComputer<T>,
replace?: boolean | undefined
): void
}['_']
type BivariantStateComputer<T> = {
_(state: T): T | Partial<T>
}['_']
Copy link
Member

Choose a reason for hiding this comment

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

Yeah, inlining seems simple enough and more consistent.

Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

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

Thanks all for helping with types.

@dai-shi dai-shi merged commit 62d1cab into pmndrs:main Jul 16, 2022
@dai-shi dai-shi changed the title Mark more methods bivariant fix(types): Mark more methods bivariant Jul 17, 2022
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