kakasoo / kakasoo/DeepStrictTypes

[BUG] `readonly` array modifier lost during type transformation

Open
#47 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
64
Forks
2
PR merge metrics
No merged PRs in 30d

Description

# 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**

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

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

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

**Affected Files**

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

**Fix**

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

```typescript
// DeepStrictObjectKeys.ts:109 (existing reference pattern)
: DeepStrictUnbrand 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` 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:**
```bash
npm run build:test && npm run test
npm run prettier
```

Contributor guide

Open the contributing guide

Research direction

Start with the affected branches in src/types/DeepDateToString.ts, src/types/DeepStrictMerge.ts, src/types/DeepMerge.ts, and src/types/DeepStrictUnbrand.ts, using the readonly-array pattern in DeepStrictObjectKeys.ts as a reference. Add coverage for the listed readonly arrays, tuples, nesting, and branded types using Equal. Run npm run build:test && npm run test, then npm run prettier; done means readonly modifiers and existing mutable-array behavior are preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.