web 3d图形渲染器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
10 KiB

  1. type Tail<T extends any[]> = ((...t: T) => any) extends (
  2. _: any,
  3. ...tail: infer TT
  4. ) => any
  5. ? TT
  6. : []
  7. /** Object types that should never be mapped */
  8. type AtomicObject =
  9. | Function
  10. | WeakMap<any, any>
  11. | WeakSet<any>
  12. | Promise<any>
  13. | Date
  14. | RegExp
  15. | Boolean
  16. | Number
  17. | String
  18. export type Draft<T> = T extends AtomicObject
  19. ? T
  20. : T extends Map<infer K, infer V>
  21. ? DraftMap<K, V>
  22. : T extends Set<infer V>
  23. ? DraftSet<V>
  24. : T extends object
  25. ? {-readonly [K in keyof T]: Draft<T[K]>}
  26. : T
  27. // Inline these in ts 3.7
  28. interface DraftMap<K, V> extends Map<Draft<K>, Draft<V>> {}
  29. // Inline these in ts 3.7
  30. interface DraftSet<V> extends Set<Draft<V>> {}
  31. /** Convert a mutable type into a readonly type */
  32. export type Immutable<T> = T extends AtomicObject
  33. ? T
  34. : T extends Map<infer K, infer V> // Ideally, but wait for TS 3.7: ? Omit<ImmutableMap<K, V>, "set" | "delete" | "clear">
  35. ? ImmutableMap<K, V>
  36. : T extends Set<infer V> // Ideally, but wait for TS 3.7: ? Omit<ImmutableSet<V>, "add" | "delete" | "clear">
  37. ? ImmutableSet<V>
  38. : T extends object
  39. ? {readonly [K in keyof T]: Immutable<T[K]>}
  40. : T
  41. interface ImmutableMap<K, V> extends Map<Immutable<K>, Immutable<V>> {}
  42. interface ImmutableSet<V> extends Set<Immutable<V>> {}
  43. export interface Patch {
  44. op: "replace" | "remove" | "add"
  45. path: (string | number)[]
  46. value?: any
  47. }
  48. export type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void
  49. /** Converts `nothing` into `undefined` */
  50. type FromNothing<T> = T extends Nothing ? undefined : T
  51. /** The inferred return type of `produce` */
  52. export type Produced<Base, Return> = Return extends void
  53. ? Base
  54. : Return extends Promise<infer Result>
  55. ? Promise<Result extends void ? Base : FromNothing<Result>>
  56. : FromNothing<Return>
  57. /**
  58. * The `produce` function takes a value and a "recipe function" (whose
  59. * return value often depends on the base state). The recipe function is
  60. * free to mutate its first argument however it wants. All mutations are
  61. * only ever applied to a __copy__ of the base state.
  62. *
  63. * Pass only a function to create a "curried producer" which relieves you
  64. * from passing the recipe function every time.
  65. *
  66. * Only plain objects and arrays are made mutable. All other objects are
  67. * considered uncopyable.
  68. *
  69. * Note: This function is __bound__ to its `Immer` instance.
  70. *
  71. * @param {any} base - the initial state
  72. * @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
  73. * @param {Function} patchListener - optional function that will be called with all the patches produced here
  74. * @returns {any} a new state, or the initial state if nothing was modified
  75. */
  76. export interface IProduce {
  77. /** Curried producer */
  78. <
  79. Recipe extends (...args: any[]) => any,
  80. Params extends any[] = Parameters<Recipe>,
  81. T = Params[0]
  82. >(
  83. recipe: Recipe
  84. ): <Base extends Immutable<T>>(
  85. base: Base,
  86. ...rest: Tail<Params>
  87. ) => Produced<Base, ReturnType<Recipe>>
  88. // ^ by making the returned type generic, the actual type of the passed in object is preferred
  89. // over the type used in the recipe. However, it does have to satisfy the immutable version used in the recipe
  90. // Note: the type of S is the widened version of T, so it can have more props than T, but that is technically actually correct!
  91. /** Curried producer with initial state */
  92. <
  93. Recipe extends (...args: any[]) => any,
  94. Params extends any[] = Parameters<Recipe>,
  95. T = Params[0]
  96. >(
  97. recipe: Recipe,
  98. initialState: Immutable<T>
  99. ): <Base extends Immutable<T>>(
  100. base?: Base,
  101. ...rest: Tail<Params>
  102. ) => Produced<Base, ReturnType<Recipe>>
  103. /** Normal producer */
  104. <Base, D = Draft<Base>, Return = void>(
  105. base: Base,
  106. recipe: (draft: D) => Return,
  107. listener?: PatchListener
  108. ): Produced<Base, Return>
  109. }
  110. export const produce: IProduce
  111. export default produce
  112. /**
  113. * Like `produce`, but instead of just returning the new state,
  114. * a tuple is returned with [nextState, patches, inversePatches]
  115. *
  116. * Like produce, this function supports currying
  117. */
  118. export interface IProduceWithPatches {
  119. /** Curried producer */
  120. <
  121. Recipe extends (...args: any[]) => any,
  122. Params extends any[] = Parameters<Recipe>,
  123. T = Params[0]
  124. >(
  125. recipe: Recipe
  126. ): <Base extends Immutable<T>>(
  127. base: Base,
  128. ...rest: Tail<Params>
  129. ) => [Produced<Base, ReturnType<Recipe>>, Patch[], Patch[]]
  130. // ^ by making the returned type generic, the actual type of the passed in object is preferred
  131. // over the type used in the recipe. However, it does have to satisfy the immutable version used in the recipe
  132. // Note: the type of S is the widened version of T, so it can have more props than T, but that is technically actually correct!
  133. /** Curried producer with initial state */
  134. <
  135. Recipe extends (...args: any[]) => any,
  136. Params extends any[] = Parameters<Recipe>,
  137. T = Params[0]
  138. >(
  139. recipe: Recipe,
  140. initialState: Immutable<T>
  141. ): <Base extends Immutable<T>>(
  142. base?: Base,
  143. ...rest: Tail<Params>
  144. ) => [Produced<Base, ReturnType<Recipe>>, Patch[], Patch[]]
  145. /** Normal producer */
  146. <Base, D = Draft<Base>, Return = void>(
  147. base: Base,
  148. recipe: (draft: D) => Return
  149. ): [Produced<Base, Return>, Patch[], Patch[]]
  150. }
  151. export const produceWithPatches: IProduceWithPatches
  152. /** Use a class type for `nothing` so its type is unique */
  153. declare class Nothing {
  154. // This lets us do `Exclude<T, Nothing>`
  155. private _: any
  156. }
  157. /**
  158. * The sentinel value returned by producers to replace the draft with undefined.
  159. */
  160. export const nothing: Nothing
  161. /**
  162. * To let Immer treat your class instances as plain immutable objects
  163. * (albeit with a custom prototype), you must define either an instance property
  164. * or a static property on each of your custom classes.
  165. *
  166. * Otherwise, your class instance will never be drafted, which means it won't be
  167. * safe to mutate in a produce callback.
  168. */
  169. export const immerable: unique symbol
  170. /**
  171. * Pass true to automatically freeze all copies created by Immer.
  172. *
  173. * By default, auto-freezing is disabled in production.
  174. */
  175. export function setAutoFreeze(autoFreeze: boolean): void
  176. /**
  177. * Pass true to use the ES2015 `Proxy` class when creating drafts, which is
  178. * always faster than using ES5 proxies.
  179. *
  180. * By default, feature detection is used, so calling this is rarely necessary.
  181. */
  182. export function setUseProxies(useProxies: boolean): void
  183. /**
  184. * Apply an array of Immer patches to the first argument.
  185. *
  186. * This function is a producer, which means copy-on-write is in effect.
  187. */
  188. export function applyPatches<S>(base: S, patches: Patch[]): S
  189. /**
  190. * Create an Immer draft from the given base state, which may be a draft itself.
  191. * The draft can be modified until you finalize it with the `finishDraft` function.
  192. */
  193. export function createDraft<T>(base: T): Draft<T>
  194. /**
  195. * Finalize an Immer draft from a `createDraft` call, returning the base state
  196. * (if no changes were made) or a modified copy. The draft must *not* be
  197. * mutated afterwards.
  198. *
  199. * Pass a function as the 2nd argument to generate Immer patches based on the
  200. * changes that were made.
  201. */
  202. export function finishDraft<T>(draft: T, listener?: PatchListener): Immutable<T>
  203. /** Get the underlying object that is represented by the given draft */
  204. export function original<T>(value: T): T | void
  205. /** Takes a snapshot of the current state of a draft and finalizes it (but without freezing). This is a great utility to print the current state during debugging (no Proxies in the way). The output of current can also be safely leaked outside the producer. */
  206. export function current<T>(value: T): T
  207. /** Returns true if the given value is an Immer draft */
  208. export function isDraft(value: any): boolean
  209. /** Returns true if the given value can be drafted by Immer */
  210. export function isDraftable(value: any): boolean
  211. export class Immer {
  212. constructor(config: {
  213. useProxies?: boolean
  214. autoFreeze?: boolean
  215. onAssign?: (
  216. state: ImmerState,
  217. prop: string | number,
  218. value: unknown
  219. ) => void
  220. onDelete?: (state: ImmerState, prop: string | number) => void
  221. onCopy?: (state: ImmerState) => void
  222. })
  223. /**
  224. * The `produce` function takes a value and a "recipe function" (whose
  225. * return value often depends on the base state). The recipe function is
  226. * free to mutate its first argument however it wants. All mutations are
  227. * only ever applied to a __copy__ of the base state.
  228. *
  229. * Pass only a function to create a "curried producer" which relieves you
  230. * from passing the recipe function every time.
  231. *
  232. * Only plain objects and arrays are made mutable. All other objects are
  233. * considered uncopyable.
  234. *
  235. * Note: This function is __bound__ to its `Immer` instance.
  236. *
  237. * @param {any} base - the initial state
  238. * @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
  239. * @param {Function} patchListener - optional function that will be called with all the patches produced here
  240. * @returns {any} a new state, or the initial state if nothing was modified
  241. */
  242. produce: IProduce
  243. /**
  244. * When true, `produce` will freeze the copies it creates.
  245. */
  246. readonly autoFreeze: boolean
  247. /**
  248. * When true, drafts are ES2015 proxies.
  249. */
  250. readonly useProxies: boolean
  251. /**
  252. * Pass true to automatically freeze all copies created by Immer.
  253. *
  254. * By default, auto-freezing is disabled in production.
  255. */
  256. setAutoFreeze(autoFreeze: boolean): void
  257. /**
  258. * Pass true to use the ES2015 `Proxy` class when creating drafts, which is
  259. * always faster than using ES5 proxies.
  260. *
  261. * By default, feature detection is used, so calling this is rarely necessary.
  262. */
  263. setUseProxies(useProxies: boolean): void
  264. }
  265. export interface ImmerState<T = any> {
  266. parent?: ImmerState
  267. base: T
  268. copy: T
  269. assigned: {[prop: string]: boolean; [index: number]: boolean}
  270. }
  271. // Backward compatibility with --target es5
  272. declare global {
  273. interface Set<T> {}
  274. interface Map<K, V> {}
  275. interface WeakSet<T> {}
  276. interface WeakMap<K extends object, V> {}
  277. }
  278. export declare function enableAllPlugins(): void
  279. export declare function enableES5(): void
  280. export declare function enableMapSet(): void
  281. export declare function enablePatches(): void