diff --git a/__tests__/produce.ts b/__tests__/produce.ts index 9ad963c3..912c9fea 100644 --- a/__tests__/produce.ts +++ b/__tests__/produce.ts @@ -771,6 +771,24 @@ it("allows for mixed property value types", () => { }) }) +it("allows higher order type inference", () => { + function _test() { + type S = {prop: A | undefined} + produce( + draft => { + draft.prop = undefined + }, + {prop: undefined} as S + ) + } +}) + +it("supports tuples with spread", () => { + type State = [boolean, ...number[]] + const foo = (x: State) => x + produce(x => foo(x)) +}) + it("#877 - produce with typed state generic requires initial state", () => { const reducerNoInitial = produce<{count: number}, [{type: "inc"}]>( (draft, action: {type: "inc"}) => { diff --git a/src/types/types-external.ts b/src/types/types-external.ts index bd240faa..8c8fedd9 100644 --- a/src/types/types-external.ts +++ b/src/types/types-external.ts @@ -30,12 +30,25 @@ type WeakReferences = IfAvailable> | IfAvailable> export type WritableDraft = T extends any[] ? number extends T["length"] - ? Draft[] + ? IsPlainArray extends true + ? Draft[] + : WritableNonArrayDraft : WritableNonArrayDraft : WritableNonArrayDraft +/** + * Distinguishes plain array types (`number[]`, `readonly string[]`, etc.) from + * tuple types — including variadic tuples like `[boolean, ...number[]]` — whose + * `length` is also `number` but must not be widened to `Element[]`. + */ +type IsPlainArray = T extends readonly (infer U)[] + ? U[] extends T + ? true + : false + : false + type WritableNonArrayDraft = { - -readonly [K in keyof T]: T[K] extends infer V + -readonly [K in keyof T]: {_: T[K]} extends {_: infer V} ? V extends object ? Draft : V