Skip to content

Commit

Permalink
feat: βž• add MarkWritable (#296)
Browse files Browse the repository at this point in the history
* feat: βž• add MarkWritable πŸš€

* test: πŸ§ͺ MarkWritable

* docs: βž• add MarkWritable πŸ“„

* docs: πŸ“„ changeset

* docs: πŸ“„ fix typo in README

* docs: πŸ“„ update changeset
  • Loading branch information
Beraliv committed Jan 31, 2022
1 parent fa03dda commit 6b27ee4
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/pink-bats-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ts-essentials": minor
---

Add `MarkWritable` which unsets readonly for specified keys
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ If you use any [functions](https://github.com/krzkaczor/ts-essentials/blob/maste
- [MarkRequired](#MarkRequired)
- [MarkOptional](#MarkOptional)
- [MarkReadonly](#MarkReadonly)
- [MarkWritable](#MarkWritable)
- [ReadonlyKeys](#ReadonlyKeys)
- [WritableKeys](#WritableKeys)
- [OptionalKeys](#OptionalKeys)
Expand Down Expand Up @@ -773,6 +774,30 @@ type UserThatCannotChangeName = MarkReadonly<User, "name">;
// }
```

### MarkWritable

Useful when you want to make some properties writable (or unset `readonly`) without creating a separate type.

```typescript
interface User {
readonly id: number;
readonly name: string;
readonly email: string;
readonly password: string;
}

type UserThatCanChangeName = MarkWritable<User, "name">;

// Result:

// {
// readonly id: number;
// name: string;
// readonly email: string;
// readonly password: string;
// }
```

### ReadonlyKeys

Gets keys of an object which are readonly.
Expand Down
3 changes: 3 additions & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,9 @@ export type MarkOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>
/** Mark some properties as readonly, leaving others unchanged */
export type MarkReadonly<T, K extends keyof T> = Omit<T, K> & Readonly<Pick<T, K>>;

/** Mark some properties as writable, leaving others unchanged */
export type MarkWritable<T, K extends keyof T> = Omit<T, K> & Writable<Pick<T, K>>;

/** Convert union type to intersection #darkmagic */
export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;

Expand Down
34 changes: 34 additions & 0 deletions test/mark-writable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { AssertTrue as Assert, IsExact } from "conditional-type-checks";
import { MarkWritable, Writable, ReadonlyKeys, WritableKeys } from "../lib/types";

function testMarkWritable() {
type Example = {
readonly readonly1: Date;
readonly readonly2: RegExp;
required1: number;
required2: string;
optional1?: null;
optional2?: boolean;
};

type cases = [
Assert<IsExact<MarkWritable<Example, never>, Example>>,
Assert<IsExact<MarkWritable<Example, WritableKeys<Example>>, Example>>,
Assert<IsExact<MarkWritable<Example, ReadonlyKeys<Example>>, Writable<Example>>>,
Assert<
IsExact<
MarkWritable<Example, "readonly1">,
{
readonly1: Date;
readonly readonly2: RegExp;
required1: number;
required2: string;
optional1?: null;
optional2?: boolean;
}
>
>,
// @ts-expect-error do NOT support union types
MarkWritable<Example | { a: 1 }, "readonly1">,
];
}

0 comments on commit 6b27ee4

Please sign in to comment.