Skip to content

Commit

Permalink
Add WritableKeysOf and ReadonlyKeysOf type (#619)
Browse files Browse the repository at this point in the history
  • Loading branch information
kkmuffme authored May 20, 2023
1 parent c2bf374 commit a3e1589
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 0 deletions.
2 changes: 2 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export type {OverrideProperties} from './source/override-properties';
export type {HasOptionalKeys} from './source/has-optional-keys';
export type {RequiredKeysOf} from './source/required-keys-of';
export type {HasRequiredKeys} from './source/has-required-keys';
export type {ReadonlyKeysOf} from './source/readonly-keys-of';
export type {WritableKeysOf} from './source/writable-keys-of';
export type {Spread} from './source/spread';
export type {TupleToUnion} from './source/tuple-to-union';
export type {IsEqual} from './source/is-equal';
Expand Down
2 changes: 2 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ Click the type names for complete docs.
- [`HasOptionalKeys`](source/has-optional-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any optional fields.
- [`RequiredKeysOf`](source/required-keys-of.d.ts) - Extract all required keys from the given type.
- [`HasRequiredKeys`](source/has-required-keys.d.ts) - Create a `true`/`false` type depending on whether the given type has any required fields.
- [`ReadonlyKeysOf`](source/readonly-keys-of.d.ts) - Extract all writable (non-readonly) keys from the given type.
- [`WritableKeysOf`](source/writable-keys-of.d.ts) - Extract all readonly keys from the given type.
- [`Spread`](source/spread.d.ts) - Mimic the type inferred by TypeScript when merging two objects or two arrays/tuples using the spread syntax.
- [`IsEqual`](source/is-equal.d.ts) - Returns a boolean for whether the two given types are equal.
- [`TaggedUnion`](source/tagged-union.d.ts) - Create a union of types that share a common discriminant property.
Expand Down
29 changes: 29 additions & 0 deletions source/readonly-keys-of.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type {IsEqual} from './is-equal';

/**
Extract all readonly keys from the given type.
This is useful when you want to create a new type that contains readonly keys only.
@example
```
import type {ReadonlyKeysOf} from 'type-fest';
interface User {
name: string;
surname: string;
readonly id: number;
}
type UpdateResponse<Entity extends object> = Pick<Entity, ReadonlyKeysOf<Entity>>;
const update1: UpdateResponse<User> = {
id: 123,
};
```
@category Utilities
*/
export type ReadonlyKeysOf<T> = NonNullable<{
[P in keyof T]: IsEqual<{[Q in P]: T[P]}, {readonly [Q in P]: T[P]}> extends true ? P : never
}[keyof T]>;
30 changes: 30 additions & 0 deletions source/writable-keys-of.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type {IsEqual} from './is-equal';

/**
Extract all writable keys from the given type.
This is useful when you want to create a new type that contains writable keys only.
@example
```
import type {WritableKeysOf} from 'type-fest';
interface User {
name: string;
surname: string;
readonly id: number;
}
type UpdateRequest<Entity extends object> = Pick<Entity, WritableKeysOf<Entity>>;
const update1: UpdateRequest<User> = {
name: 'Alice',
surname: 'Acme',
};
```
@category Utilities
*/
export type WritableKeysOf<T> = NonNullable<{
[P in keyof T]: IsEqual<{[Q in P]: T[P]}, {readonly [Q in P]: T[P]}> extends false ? P : never
}[keyof T]>;
29 changes: 29 additions & 0 deletions test-d/readonly-keys-of.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {expectType} from 'tsd';
import type {ReadonlyKeysOf} from '../index';

type TestType1 = {
a: string;
readonly b: boolean;
};

type TestType2 = {
readonly a: string;
readonly b: boolean;
};

type TestType3 = {
a: string;
b: boolean;
};

type ReadonlyKeysOf1 = ReadonlyKeysOf<TestType1>;
type ReadonlyKeysOf2 = ReadonlyKeysOf<TestType2>;
type ReadonlyKeysOf3 = ReadonlyKeysOf<TestType3>;

declare const test1: ReadonlyKeysOf1;
declare const test2: ReadonlyKeysOf2;
declare const test3: ReadonlyKeysOf3;

expectType<'b'>(test1);
expectType<'a' | 'b'>(test2);
expectType<never>(test3);
29 changes: 29 additions & 0 deletions test-d/writable-keys-of.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {expectType} from 'tsd';
import type {WritableKeysOf} from '../index';

type TestType1 = {
readonly a: string;
b: boolean;
};

type TestType2 = {
a: string;
b: boolean;
};

type TestType3 = {
readonly a: string;
readonly b: boolean;
};

type WritableKeysOf1 = WritableKeysOf<TestType1>;
type WritableKeysOf2 = WritableKeysOf<TestType2>;
type WritableKeysOf3 = WritableKeysOf<TestType3>;

declare const test1: WritableKeysOf1;
declare const test2: WritableKeysOf2;
declare const test3: WritableKeysOf3;

expectType<'b'>(test1);
expectType<'a' | 'b'>(test2);
expectType<never>(test3);

0 comments on commit a3e1589

Please sign in to comment.