Skip to content

[BUG] readonly array modifier lost during type transformation #47

@kakasoo

Description

@kakasoo

Bug Report

Description

In DeepDateToString, DeepStrictMerge, DeepMerge, and DeepStrictUnbrand, when a readonly array is provided as input, the readonly modifier is lost in the output type. Since type safety is the core focus of this library, loss of modifier information is a bug.

Type Issue Example

When a readonly array is provided as input, the output is converted to a mutable Array.

Type Input

// === DeepDateToString ===
type Input1 = readonly { date: Date }[];
type Result1 = DeepDateToString<Input1>;
// Expected: readonly { date: string }[]
// Actual:   { date: string }[]  (readonly lost)

// === DeepStrictMerge ===
type Target = readonly { a: number }[];
type Source = readonly { b: string }[];
type Result2 = DeepStrictMerge<Target, Source>;
// Expected: readonly { a: number; b: string }[]
// Actual:   { a: number; b: string }[]  (readonly lost)

// === DeepStrictUnbrand ===
type Input3 = readonly { a: number & { __brand: 'ID' } }[];
type Result3 = DeepStrictUnbrand<Input3>;
// Expected: readonly { a: number }[]
// Actual:   { a: number }[]  (readonly lost)

Affected Files

File Line Issue
src/types/DeepDateToString.ts 29-30 Only matches Array<infer I>, no readonly array branch
src/types/DeepStrictMerge.ts 13-15 Only matches Array<infer TE>, no readonly array branch
src/types/DeepMerge.ts 66-73 Same pattern
src/types/DeepStrictUnbrand.ts 56-68 Only matches Array<infer I>, no readonly array branch

Fix

Add a readonly (infer I)[] branch after each Array<infer I> branch to handle readonly arrays separately. This pattern is already used in DeepStrictObjectKeys:

// DeepStrictObjectKeys.ts:109 (existing reference pattern)
: DeepStrictUnbrand<Target> extends readonly (infer Element)[]

Test Requirements

All changes must include the following tests:

  1. Backward Compatibility

    • All existing mutable array tests must pass (npm run build:test && npm run test)
    • Add tests to verify that existing type behavior remains unchanged
  2. Fix Verification

    • For each type, verify readonly is preserved when inputting a readonly array using the Equal<Question, Answer> pattern
  3. Complex Type Stability

    • readonly { nested: { deep: Date } }[] (readonly + nesting + Date)
    • readonly [{ a: 1 }, { b: 2 }] (readonly tuple)
    • readonly { a: number & MinLength<1> }[] (readonly + branded)
    • readonly (readonly { a: 1 }[])[] (2D readonly array)
    • readonly { items: readonly { date: Date }[] }[] (nested readonly arrays)

How to verify:

npm run build:test && npm run test
npm run prettier

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions