Skip to content

Commit

Permalink
Rewrite TakeTwo, SkipTwo and Mutate to make them work for older…
Browse files Browse the repository at this point in the history
… ts versions too (#1348)

* create tsc v4.3.5 snapshot

* rewrite `TakeTwo` and `SkipTwo`
...to work with both pre 4.3.5 and post 4.3.5 subtyping rules.

The type `Test` in the following snippet resolves to `"yes"` for
<=4.3.5 but `"no"` for >4.3.5
```ts
type Test = [string, number?] extends [unknown] ? "yes" : "no"
```
(note 4.3.5 is bisected via typescript playground which skips
some versions so it might not be super accurate, but it's
accurate enough)

* fix lint

* fix pretest script to use tsc script instead of tsc bin

* revert tests

* add a workflow to test with old tsc

* fix typo

* oops, we need to run tsc

* test against build

* fix regex 🤦‍♂️

* oops, something was missing

* build in advance

* wip: more older versions

* wip: downgrade jest types

* minimum ts version 4.1.5

* minor fix

* make `Mutate` more complete
...wrt to the domain `StoreMutatorIdentifier[]` to help the type-checker

* fix lint

Co-authored-by: daishi <daishi@axlight.com>
  • Loading branch information
devanshj and dai-shi authored Oct 9, 2022
1 parent ae4cc7f commit 93b5a43
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test-multiple-versions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '12'
node-version: '14'
cache: yarn
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- run: yarn install --frozen-lockfile --check-files
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/test-old-typescript.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Test Old TypeScript

on:
push:
branches: [main]
pull_request:
types: [opened, synchronize]

jobs:
test_matrix:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
typescript:
- 4.8.4
- 4.7.4
- 4.6.4
- 4.5.5
- 4.4.4
- 4.3.5
- 4.2.3
- 4.1.5
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '14'
cache: yarn
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
- run: yarn install --frozen-lockfile --check-files
- run: yarn build
- name: Patch for Old TS
run: |
sed -i~ "s/\/\/ @ts-expect-error.*\[LATEST-TS-ONLY\]//" tests/*.tsx
sed -i~ "s/\"exactOptionalPropertyTypes\": true,//" tsconfig.json
sed -i~ "s/\"zustand\": \[\"\.\/src\/index\.ts\"\],/\"zustand\": [\".\/dist\/index.d.ts\"],/" tsconfig.json
sed -i~ "s/\"zustand\/\*\": \[\"\.\/src\/\*\.ts\"\]/\"zustand\/*\": [\".\/dist\/*.d.ts\"]/" tsconfig.json
sed -i~ "s/\"include\": .*/\"include\": [\"src\/types.d.ts\", \"dist\/**\/*\", \"tests\/**\/*\"],/" tsconfig.json
- name: Test ${{ matrix.typescript }}
run: |
yarn add -D typescript@${{ matrix.typescript }}
yarn tsc --noEmit
17 changes: 9 additions & 8 deletions src/middleware/devtools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,19 @@ type Message = {
state?: any
}

type Cast<T, U> = T extends U ? T : U
type Write<T, U> = Omit<T, keyof U> & U
type TakeTwo<T> = T extends []
type TakeTwo<T> = T extends { length: 0 }
? [undefined, undefined]
: T extends [unknown]
? [...a0: T, a1: undefined]
: T extends [unknown?]
? [...a0: T, a1: undefined]
: T extends [unknown, unknown]
: T extends { length: 1 }
? [...a0: Cast<T, unknown[]>, a1: undefined]
: T extends { length: 0 | 1 }
? [...a0: Cast<T, unknown[]>, a1: undefined]
: T extends { length: 2 }
? T
: T extends [unknown, unknown?]
: T extends { length: 1 | 2 }
? T
: T extends [unknown?, unknown?]
: T extends { length: 0 | 1 | 2 }
? T
: T extends [infer A0, infer A1, ...unknown[]]
? [A0, A1]
Expand Down
6 changes: 3 additions & 3 deletions src/middleware/immer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ declare module '../vanilla' {
}

type Write<T, U> = Omit<T, keyof U> & U
type SkipTwo<T> = T extends []
type SkipTwo<T> = T extends { length: 0 }
? []
: T extends [unknown]
: T extends { length: 1 }
? []
: T extends [unknown?]
: T extends { length: 0 | 1 }
? []
: T extends [unknown, unknown, ...infer A]
? A
Expand Down
4 changes: 3 additions & 1 deletion src/vanilla.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ export interface StoreApi<T> {

type Get<T, K, F = never> = K extends keyof T ? T[K] : F

export type Mutate<S, Ms> = Ms extends []
export type Mutate<S, Ms> = number extends Ms['length' & keyof Ms]
? S
: Ms extends []
? S
: Ms extends [[infer Mi, infer Ma], ...infer Mrs]
? Mutate<StoreMutators<S, Ma>[Mi & StoreMutatorIdentifier], Mrs>
Expand Down
8 changes: 4 additions & 4 deletions tests/types.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ it('should have correct (partial) types for setState', () => {

const store = create<Count>((set) => ({
count: 0,
// @ts-expect-error we shouldn't be able to set count to undefined
// @ts-expect-error we shouldn't be able to set count to undefined [LATEST-TS-ONLY]
a: () => set(() => ({ count: undefined })),
// @ts-expect-error we shouldn't be able to set count to undefined
// @ts-expect-error we shouldn't be able to set count to undefined [LATEST-TS-ONLY]
b: () => set({ count: undefined }),
c: () => set({ count: 1 }),
}))
Expand All @@ -124,9 +124,9 @@ it('should have correct (partial) types for setState', () => {
store.setState({})
store.setState((previous) => previous)

// @ts-expect-error type undefined is not assignable to type number
// @ts-expect-error type undefined is not assignable to type number [LATEST-TS-ONLY]
store.setState({ count: undefined })
// @ts-expect-error type undefined is not assignable to type number
// @ts-expect-error type undefined is not assignable to type number [LATEST-TS-ONLY]
store.setState((state) => ({ ...state, count: undefined }))
})

Expand Down

0 comments on commit 93b5a43

Please sign in to comment.