remutable-ts 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +10 -0
- package/package.json +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Dan Funder Christoffersen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# remutable-ts
|
|
2
|
+
|
|
3
|
+
remutable-ts provides a simple and **type-safe** way to remove readonly
|
|
4
|
+
modifiers from types in TypeScript.
|
|
5
|
+
|
|
6
|
+
This is useful when you:
|
|
7
|
+
|
|
8
|
+
- Need to **mutate objects** that are defined as **readonly** (e.g. libraries,
|
|
9
|
+
framework types).
|
|
10
|
+
- Prefer solutions with **no runtime** overhead.
|
|
11
|
+
|
|
12
|
+
### ⚡ Why not just remove readonly?
|
|
13
|
+
|
|
14
|
+
Keeping `readonly` by default is safer as it prevents unintended mutations.
|
|
15
|
+
`remutable-ts` allows controlled mutation, even in external modules where
|
|
16
|
+
needed, giving you flexibility without sacrificing type safety.
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
For **usage as a devDependency with zero runtime**:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install --save-dev remutable-ts
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### 1. Make any type mutable
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
type Example = {
|
|
32
|
+
readonly a: number;
|
|
33
|
+
readonly b: string;
|
|
34
|
+
readonly nested: {
|
|
35
|
+
readonly c: boolean; // Note nested properties will remain readonly
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const example: Example = {
|
|
40
|
+
a: 1,
|
|
41
|
+
b: "hello",
|
|
42
|
+
nested: {
|
|
43
|
+
c: true
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Inline example usage
|
|
48
|
+
(example as Mutable<Example>).a = 2; ✅ allowed now
|
|
49
|
+
|
|
50
|
+
// Using Mutable<T> to get a fully writable type
|
|
51
|
+
const writableExample = example as Mutable<Example>;
|
|
52
|
+
|
|
53
|
+
writableExample.a = 2; ✅ allowed now
|
|
54
|
+
writableExample.b = "world"; ✅ allowed now
|
|
55
|
+
// writableExample.nested.c = false; // Error: Cannot assign to 'c' because it remains a read-only property.
|
|
56
|
+
|
|
57
|
+
console.log("Original example:", example);
|
|
58
|
+
console.log("Writable example before mutation:", writableExample);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2. Using mutable(this) inside a class to get a writable view
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
//
|
|
65
|
+
class MyClass {
|
|
66
|
+
readonly x: number = 5; // Always apply type to literal values
|
|
67
|
+
readonly name: string = "Alice"; // Always apply type to literal values
|
|
68
|
+
|
|
69
|
+
update() {
|
|
70
|
+
(this as Mutable<this>).x = 20; ✅ allowed now
|
|
71
|
+
|
|
72
|
+
// or using mutable helper function
|
|
73
|
+
mutable(this).name = "Bob"; ✅ allowed now
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const myInstance = new MyClass();
|
|
78
|
+
console.log("Before update:", myInstance);
|
|
79
|
+
myInstance.update();
|
|
80
|
+
console.log("After update:", myInstance);
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### ⚠️ Gotcha: literal types
|
|
84
|
+
|
|
85
|
+
When you initialize a readonly property with a literal value (e.g.,
|
|
86
|
+
`readonly score = 0`), TypeScript infers a literal type (`0`), not the broader
|
|
87
|
+
type (`number`). This can cause assignment errors when using `Mutable<T>` or
|
|
88
|
+
`mutable<T>()`, since you can't assign, say, `1` to a property of type `0`.
|
|
89
|
+
|
|
90
|
+
**Recommendation:** Explicitly type such properties to avoid this issue:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const score: Mutable<{ readonly score: number }> = { score: 0 }; // ✅ Use an explicit type
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
This ensures `Mutable<T>` and `mutable<T>()` work as expected for assignments.
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A utility type that removes readonly modifiers from all properties of T,
|
|
3
|
+
* keeping the type structure intact with no runtime impact.
|
|
4
|
+
*/
|
|
5
|
+
export type Mutable<T> = {
|
|
6
|
+
-readonly [K in keyof T]: T[K];
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Returns the given object typed as Mutable<T>, effectively removing readonly
|
|
10
|
+
* modifiers from its properties. This function preserves the original type shape and only has i minimal runtime impact.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mutable<T>(obj: T): Mutable<T>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mutable = mutable;
|
|
4
|
+
/**
|
|
5
|
+
* Returns the given object typed as Mutable<T>, effectively removing readonly
|
|
6
|
+
* modifiers from its properties. This function preserves the original type shape and only has i minimal runtime impact.
|
|
7
|
+
*/
|
|
8
|
+
function mutable(obj) {
|
|
9
|
+
return obj;
|
|
10
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "remutable-ts",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "TypeScript utility to safely bypass readonly at compile-time with zero runtime overhead.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"example": "npx ts-node example/index.ts"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"typescript",
|
|
16
|
+
"utility",
|
|
17
|
+
"types",
|
|
18
|
+
"readonly",
|
|
19
|
+
"mutable"
|
|
20
|
+
],
|
|
21
|
+
"author": "FunderForge",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/Funder75/remutable-ts"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^20.11.24",
|
|
29
|
+
"typescript": "^5.3.3"
|
|
30
|
+
}
|
|
31
|
+
}
|