Skip to content

Commit 8cb831b

Browse files
authored
Merge pull request #381 from Kovensky/typescript-update
Update typescript types, fix react-spring/addons, add react-spring/hooks
2 parents b899ae2 + 147df71 commit 8cb831b

10 files changed

+376
-93
lines changed

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
"main": "web.cjs.js",
66
"module": "web.js",
77
"react-native": "native.js",
8-
"typings": "index.d.ts",
98
"private": true,
109
"sideEffects": false,
1110
"scripts": {
1211
"prebuild": "rimraf dist",
1312
"build": "npm-run-all --parallel copy rollup",
14-
"copy": "copyfiles package.json readme.md LICENSE.md index.d.ts dist && json -I -f dist/package.json -e \"this.private=false; this.devDependencies=undefined; this.scripts=undefined; this.husky=undefined; this.prettier=undefined; this.jest=undefined; this['lint-staged'] = undefined;\"",
13+
"copy": "copyfiles -f package.json readme.md LICENSE.md \"types/*\" dist && json -I -f dist/package.json -e \"this.private=false; this.devDependencies=undefined; this.scripts=undefined; this.husky=undefined; this.prettier=undefined; this.jest=undefined; this['lint-staged'] = undefined;\"",
1514
"rollup": "rollup -c",
1615
"prepare": "npm run build",
1716
"test": "jest",
@@ -72,7 +71,7 @@
7271
"@babel/preset-react": "^7.0.0",
7372
"@storybook/addon-knobs": "^3.4.11",
7473
"@storybook/react": "^3.4.11",
75-
"@types/react": "^16.7.8",
74+
"@types/react": "^16.7.17",
7675
"babel-core": "7.0.0-bridge.0",
7776
"babel-jest": "^23.6.0",
7877
"babel-plugin-react-docgen": "^2.0.0",
@@ -89,6 +88,7 @@
8988
"immer-wieder": "^1.1.5",
9089
"jest": "^23.6.0",
9190
"json": "^9.0.6",
91+
"konva": "^2.6.0",
9292
"lint-staged": "^7.3.0",
9393
"lorem-ipsum": "^1.0.6",
9494
"mock-raf": "^1.0.0",
@@ -99,6 +99,7 @@
9999
"react-dom": "16.7.0-alpha.2",
100100
"react-feather": "^1.1.4",
101101
"react-helmet": "^5.2.0",
102+
"react-konva": "^16.6.31",
102103
"react-test-renderer": "^16.5.2",
103104
"react-testing-library": "^5.2.0",
104105
"react-transition-group": "^2.5.0",

tsconfig.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"noFallthroughCasesInSwitch": true,
99
"noEmitOnError": true,
1010
"forceConsistentCasingInFileNames": true,
11-
"lib": ["es2016", "dom"]
11+
"lib": ["es2016", "dom"],
12+
"skipLibCheck": false
1213
},
13-
"include": ["tests/**/*.tsx"]
14+
"include": ["tests/**/*.tsx", "types/**/*.ts"]
1415
}

types/addons.d.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Ref, PureComponent } from 'react'
2+
import { SpringConfig } from './universal'
3+
4+
interface ParallaxProps {
5+
pages: number
6+
7+
config?: SpringConfig | ((key: string) => SpringConfig)
8+
9+
scrolling?: boolean
10+
11+
horizontal?: boolean
12+
13+
ref?: Ref<Parallax>
14+
}
15+
16+
export class Parallax extends PureComponent<ParallaxProps> {
17+
scrollTo: (offset: number) => void
18+
}
19+
20+
interface ParallaxLayerProps {
21+
factor?: number
22+
23+
offset?: number
24+
25+
speed?: number
26+
}
27+
28+
export class ParallaxLayer extends PureComponent<ParallaxLayerProps> {}

types/hooks.d.ts

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import {
2+
SpringConfig,
3+
SpringBaseProps,
4+
TransitionKeyProps,
5+
State,
6+
} from './universal'
7+
export { SpringConfig, SpringBaseProps, TransitionKeyProps, State }
8+
9+
/** List from `function getForwardProps` in `src/shared/helpers` */
10+
type ExcludedProps =
11+
| 'to'
12+
| 'from'
13+
| 'config'
14+
| 'native'
15+
| 'onStart'
16+
| 'onRest'
17+
| 'onFrame'
18+
| 'children'
19+
| 'reset'
20+
| 'reverse'
21+
| 'force'
22+
| 'immediate'
23+
| 'impl'
24+
| 'inject'
25+
| 'delay'
26+
| 'attach'
27+
| 'destroyed'
28+
| 'track'
29+
| 'interpolateTo'
30+
| 'autoStart'
31+
| 'ref'
32+
export type ForwardedProps<T> = Pick<T, Exclude<keyof T, ExcludedProps>>
33+
// NOTE: because of the Partial, this makes a weak type, which can have excess props
34+
type InferFrom<T extends object> = T extends { to: infer TTo }
35+
? Partial<TTo>
36+
: Partial<ForwardedProps<T>>
37+
38+
// This is similar to "Omit<A, keyof B> & B",
39+
// but with a delayed evaluation that still allows A to be inferrable
40+
type Merge<A, B> = { [K in keyof A]: K extends keyof B ? B[K] : A[K] } & B
41+
42+
export type SetUpdateFn<DS extends object> = (ds: DS) => void
43+
44+
// The hooks do emulate React's 'ref' by accepting { ref?: React.RefObject<Controller> } and
45+
// updating it. However, there are no types for Controller, and I assume it is intentionally so.
46+
export interface HooksBaseProps
47+
extends Pick<SpringBaseProps, Exclude<keyof SpringBaseProps, 'config'>> {
48+
// there is an undocumented onKeyframesHalt which passes the controller instance,
49+
// so it also cannot be typed unless Controller types are written
50+
}
51+
52+
export interface UseSpringBaseProps extends HooksBaseProps {
53+
config?: SpringBaseProps['config']
54+
}
55+
56+
export type UseSpringProps<DS extends UseSpringBaseProps> = Merge<
57+
DS,
58+
{
59+
from?: InferFrom<DS>
60+
/**
61+
* Callback when the animation comes to a still-stand
62+
*/
63+
onRest?(ds: InferFrom<DS>): void
64+
}
65+
>
66+
67+
// there's a third value in the tuple but it's not public API (?)
68+
export function useSpring<DS extends object>(
69+
getProps: () => UseSpringProps<DS>
70+
): [ForwardedProps<DS>, SetUpdateFn<DS>]
71+
export function useSpring<DS extends object>(
72+
values: UseSpringProps<DS>
73+
): ForwardedProps<DS>
74+
75+
// there's a third value in the tuple but it's not public API (?)
76+
export function useTrail<DS extends object>(
77+
count: number,
78+
getProps: () => UseSpringProps<DS>
79+
): [ForwardedProps<DS>[], SetUpdateFn<DS>]
80+
export function useTrail<DS extends object>(
81+
count: number,
82+
values: UseSpringProps<DS>
83+
): ForwardedProps<DS>[] // safe to modify (result of .map)
84+
85+
export interface UseTransitionProps<TItem, DS extends object>
86+
extends HooksBaseProps {
87+
items: ReadonlyArray<TItem> | null | undefined
88+
/**
89+
* Spring config, or for individual items: fn(item => config)
90+
* @default config.default
91+
*/
92+
config?: SpringConfig | ((item: TItem) => SpringConfig)
93+
/**
94+
* The same keys you would normally hand over to React in a list. Keys can be specified as a key-accessor function, an array of keys, or a single value
95+
*/
96+
keys?:
97+
| ((item: TItem) => TransitionKeyProps)
98+
| ReadonlyArray<TransitionKeyProps>
99+
| TransitionKeyProps
100+
101+
/**
102+
* When true enforces that an item can only occur once instead of allowing two or more items with the same key to co-exist in a stack
103+
* @default false
104+
*/
105+
unique?: boolean
106+
/**
107+
* Trailing delay in ms
108+
*/
109+
trail?: number
110+
111+
from?: InferFrom<DS>
112+
/**
113+
* Values that apply to new elements, or: item => values
114+
* @default {}
115+
*/
116+
enter?: InferFrom<DS> | ((item: TItem) => InferFrom<DS>)
117+
/**
118+
* Values that apply to leaving elements, or: item => values
119+
* @default {}
120+
*/
121+
leave?: InferFrom<DS> | ((item: TItem) => InferFrom<DS>)
122+
/**
123+
* Values that apply to elements that are neither entering nor leaving (you can use this to update present elements), or: item => values
124+
*/
125+
update?: InferFrom<DS> | ((item: TItem) => InferFrom<DS>)
126+
}
127+
128+
export interface UseTransitionResult<TItem, DS extends object> {
129+
item: TItem
130+
key: string
131+
state: State
132+
props: ForwardedProps<DS>
133+
}
134+
135+
export function useTransition<TItem, DS extends object>(
136+
values: Merge<DS, UseTransitionProps<TItem, DS>>
137+
): UseTransitionResult<TItem, ForwardedProps<DS>>[] // result array is safe to modify
138+
139+
// higher order hooks 🤯
140+
export namespace useKeyframes {
141+
// this kind of higher order hook requires higher kinded types to type correctly at all
142+
// this is the best approximation I can get to....... and there sure are anys around 🤯
143+
144+
// the docs says it receives a 3rd argument with the component's own props, but it's only
145+
// ever called with two (https://github.com/react-spring/react-spring/blob/v7.1.3/src/hooks/KeyframesHook.js#L25)
146+
export type KeyframeFn<DS extends object> = (
147+
next: (props: UseSpringProps<DS>) => Promise<void>,
148+
cancel: () => void
149+
) => Promise<void>
150+
export interface SpringKeyframeSlotsConfig extends HooksBaseProps {
151+
// this is way too self-referential to type correctly
152+
// both onRest and config have to have vague types... 😭
153+
154+
/**
155+
* Callback when the animation comes to a still-stand
156+
*/
157+
onRest?(ds: any): void
158+
config?:
159+
| SpringConfig
160+
| ReadonlyArray<SpringConfig>
161+
| ((slot: string) => SpringConfig | ReadonlyArray<SpringConfig>)
162+
}
163+
export interface TrailKeyframeSlotsConfig<TItem>
164+
extends SpringKeyframeSlotsConfig {
165+
items: ReadonlyArray<TItem>
166+
}
167+
168+
export type ResolveKeyframeSlotValue<T> = T extends KeyframeFn<infer V>
169+
? V
170+
: T extends ReadonlyArray<infer U>
171+
? U extends KeyframeFn<infer V>
172+
? V
173+
: U extends Function // guard against accidentally putting in a KeyframeFn function
174+
? never
175+
: U
176+
: T extends Function // same guard, but when the function is not in an array
177+
? never
178+
: T
179+
180+
// fun fact: the state is literally named "undefined" if you're using this overload
181+
// the docs are vague but it seems this just loops the one animation forever?
182+
export function spring<DS extends object>(
183+
animation:
184+
| ReadonlyArray<DS>
185+
| ReadonlyArray<KeyframeFn<DS>>
186+
| KeyframeFn<DS>,
187+
initialProps?: UseSpringProps<DS>
188+
): UseSpringKeyframes<DS>
189+
// unfortunately, it's not possible to infer the type of the callback functions (if any are given)
190+
// while also remaining possible to infer the slot names. Callback functions have to be cast with
191+
// `as useKeyframes.KeyframeFn<{ ... }>`.
192+
// it's also not possible to specify the types of the values inside TSlots. This is a mess.
193+
export function spring<TSlots extends object>(
194+
slots: TSlots & SpringKeyframeSlotsConfig,
195+
// also unfortunately not possible to strongly type this either
196+
initialProps?: UseSpringProps<any>
197+
): UseSpringKeyframesWithSlots<TSlots>
198+
199+
export function trail<DS extends object>(
200+
animation:
201+
| ReadonlyArray<DS>
202+
| ReadonlyArray<KeyframeFn<DS>>
203+
| KeyframeFn<DS>,
204+
initialProps?: UseSpringProps<DS>
205+
): UseTrailKeyframes<DS>
206+
export function trail<TItem, TSlots extends object>(
207+
slots: TSlots & TrailKeyframeSlotsConfig<TItem>,
208+
initialProps?: UseSpringProps<any>
209+
): UseTrailKeyframesWithSlots<TSlots>
210+
211+
export type UseSpringKeyframesWithSlots<TSlots extends object> =
212+
// there's a bug in the implementation that actually should cause a crash
213+
// because there is no second argument, but because it is built with babel on loose mode,
214+
// it doesn't...
215+
<TSlot extends Exclude<keyof TSlots, keyof SpringKeyframeSlotsConfig>>(
216+
slot: TSlot
217+
) => ForwardedProps<ResolveKeyframeSlotValue<TSlots[TSlot]>>
218+
// this one crashes "even more" because both values are undefined
219+
export type UseSpringKeyframes<DS extends object> = () => ForwardedProps<DS>
220+
221+
export type UseTrailKeyframesWithSlots<TSlots extends object> = <
222+
TSlot extends Exclude<keyof TSlots, keyof TrailKeyframeSlotsConfig<any>>
223+
>(
224+
count: number,
225+
slot: TSlot
226+
) => ForwardedProps<ResolveKeyframeSlotValue<TSlots[TSlot]>>[]
227+
228+
export type UseTrailKeyframes<DS extends object> = (
229+
count: number
230+
) => ForwardedProps<DS>[]
231+
}

types/index.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// This is the file TypeScript will see when it looks inside the module without any sub-paths
2+
// This should just reexport the package.json's "main".
3+
export * from './web'
4+
// Add this (and to all other entry points) if a default export is ever added
5+
// export { default } from './web'

types/konva.d.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import {
2+
ForwardRefExoticComponent,
3+
ComponentPropsWithRef,
4+
ReactType,
5+
} from 'react'
6+
import { animated } from './universal'
7+
export * from './universal'
8+
9+
import * as konva from 'react-konva'
10+
11+
type KonvaComponents = Pick<
12+
typeof konva,
13+
{
14+
[K in keyof typeof konva]: typeof konva[K] extends ReactType ? K : never
15+
}[keyof typeof konva]
16+
>
17+
18+
declare const augmentedAnimated: typeof animated &
19+
{
20+
[Tag in keyof KonvaComponents]: ForwardRefExoticComponent<
21+
ComponentPropsWithRef<KonvaComponents[Tag]>
22+
>
23+
}
24+
25+
export { augmentedAnimated as animated }

types/native.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './universal'

0 commit comments

Comments
 (0)