From a29eb5b4d186965b5a28166776ede78cf52d45e9 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 26 Nov 2020 10:59:25 +0100 Subject: [PATCH 01/25] Add `SetMutable` type --- base.d.ts | 1 + source/set-mutable.d.ts | 35 +++++++++++++++++++++++++++++++++++ test-d/set-mutable.ts | 18 ++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 source/set-mutable.d.ts create mode 100644 test-d/set-mutable.ts diff --git a/base.d.ts b/base.d.ts index 9005ef9fc..f245e1355 100644 --- a/base.d.ts +++ b/base.d.ts @@ -32,6 +32,7 @@ export {Entry} from './source/entry'; export {Entries} from './source/entries'; export {SetReturnType} from './source/set-return-type'; export {Asyncify} from './source/asyncify'; +export {SetMutable} from './source/set-mutable'; // Miscellaneous export {PackageJson} from './source/package-json'; diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts new file mode 100644 index 000000000..82cab255e --- /dev/null +++ b/source/set-mutable.d.ts @@ -0,0 +1,35 @@ +import {Except} from './except'; +import {Mutable} from './mutable'; + +/** +Create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is. + +Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are mutable. + +@example +``` +import {SetMutable} from 'type-fest'; + +type Foo = { + readonly a: number; + b: string; + readonly c: boolean; +} + +type SomeMutable = SetMutable; +// type SomeRequired = { +// readonly a: number; +// b: string; // Was already mutable and still is. +// c: boolean; // Is now mutable. +// } +``` +*/ +export type SetMutable = + // Pick just the keys that are not mutable from the base type. + Except & + // Pick the keys that should be mutable from the base type and make them mutable. + Mutable> extends + // If `InferredType` extends the previous, then for each key, use the inferred type key. + infer InferredType + ? {[KeyType in keyof InferredType]: InferredType[KeyType]} + : never; diff --git a/test-d/set-mutable.ts b/test-d/set-mutable.ts new file mode 100644 index 000000000..cd1d72413 --- /dev/null +++ b/test-d/set-mutable.ts @@ -0,0 +1,18 @@ +import {expectType, expectError} from 'tsd'; +import {SetMutable} from '..'; + +// Update one required and one optional to required. +declare const variation1: SetMutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; +expectType<{readonly a: number; b: string; c: boolean}>(variation1); + +// Update two optional to required. +declare const variation2: SetMutable<{readonly a: number; readonly b: string; readonly c: boolean}, 'a' | 'b'>; +expectType<{a: number; b: string; readonly c: boolean}>(variation2); + +// Three required remain required. +declare const variation3: SetMutable<{a: number; b: string; c: boolean}, 'a' | 'b' | 'c'>; +expectType<{a: number; b: string; c: boolean}>(variation3); + +// Fail if type changes even if optional is right. +declare const variation4: SetMutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; +expectError<{readonly a: boolean; b: string; c: boolean}>(variation4); From 552c1e4cd5fc0cad11b95d05e84f4be0d21c7537 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 26 Nov 2020 13:47:32 +0100 Subject: [PATCH 02/25] Add `SetMutable` to readme --- readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.md b/readme.md index 714df7868..e0c330cbf 100644 --- a/readme.md +++ b/readme.md @@ -87,6 +87,7 @@ Click the type names for complete docs. - [`Entries`](source/entries.d.ts) - Create a type that represents the type of the entries of a collection. - [`SetReturnType`](source/set-return-type.d.ts) - Create a function type with a return type of your choice and the same parameters as the given function type. - [`Asyncify`](source/asyncify.d.ts) - Create an async version of the given function type. +- [`SetMutable`](source/set-mutable.d.ts) - Create a type that converts the given keys from `readonly` to mutable. ### Template literal types From 9b41e0ffdd1add7e9ac0a2eed6c41b42bb1fe499 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 26 Nov 2020 19:00:55 +0100 Subject: [PATCH 03/25] Update set-mutable.d.ts --- source/set-mutable.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts index 82cab255e..23e9c7419 100644 --- a/source/set-mutable.d.ts +++ b/source/set-mutable.d.ts @@ -17,7 +17,7 @@ type Foo = { } type SomeMutable = SetMutable; -// type SomeRequired = { +// type SomeMutable = { // readonly a: number; // b: string; // Was already mutable and still is. // c: boolean; // Is now mutable. From 906a629d4c5291f016bc2a58cbed82cd47a48bbb Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 28 Nov 2020 09:46:32 +0700 Subject: [PATCH 04/25] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e0c330cbf..5d14affbb 100644 --- a/readme.md +++ b/readme.md @@ -73,6 +73,7 @@ Click the type names for complete docs. - [`Opaque`](source/opaque.d.ts) - Create an [opaque type](https://codemix.com/opaque-types-in-javascript/). - [`SetOptional`](source/set-optional.d.ts) - Create a type that makes the given keys optional. - [`SetRequired`](source/set-required.d.ts) - Create a type that makes the given keys required. +- [`SetMutable`](source/set-mutable.d.ts) - Create a type that converts the given keys from `readonly` to mutable. - [`ValueOf`](source/value-of.d.ts) - Create a union of the given object's values, and optionally specify which keys to get the values from. - [`PromiseValue`](source/promise-value.d.ts) - Returns the type that is wrapped inside a `Promise`. - [`AsyncReturnType`](source/async-return-type.d.ts) - Unwrap the return type of a function that returns a `Promise`. @@ -87,7 +88,6 @@ Click the type names for complete docs. - [`Entries`](source/entries.d.ts) - Create a type that represents the type of the entries of a collection. - [`SetReturnType`](source/set-return-type.d.ts) - Create a function type with a return type of your choice and the same parameters as the given function type. - [`Asyncify`](source/asyncify.d.ts) - Create an async version of the given function type. -- [`SetMutable`](source/set-mutable.d.ts) - Create a type that converts the given keys from `readonly` to mutable. ### Template literal types From f8588adc824febc69b621b3ef42329ef04bb0e17 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 28 Nov 2020 09:47:01 +0700 Subject: [PATCH 05/25] Update base.d.ts --- base.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base.d.ts b/base.d.ts index f245e1355..d478d1fb7 100644 --- a/base.d.ts +++ b/base.d.ts @@ -18,6 +18,7 @@ export {Promisable} from './source/promisable'; export {Opaque} from './source/opaque'; export {SetOptional} from './source/set-optional'; export {SetRequired} from './source/set-required'; +export {SetMutable} from './source/set-mutable'; export {ValueOf} from './source/value-of'; export {PromiseValue} from './source/promise-value'; export {AsyncReturnType} from './source/async-return-type'; @@ -32,7 +33,6 @@ export {Entry} from './source/entry'; export {Entries} from './source/entries'; export {SetReturnType} from './source/set-return-type'; export {Asyncify} from './source/asyncify'; -export {SetMutable} from './source/set-mutable'; // Miscellaneous export {PackageJson} from './source/package-json'; From 8fd0d33a7243cde20415abd71e2e54954a6e0be3 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Sat, 28 Nov 2020 14:05:20 +0100 Subject: [PATCH 06/25] Remove default type arg and add additional docs --- source/mutable.d.ts | 8 ++++++-- source/set-mutable.d.ts | 8 +++++--- source/set-optional.d.ts | 2 +- source/set-required.d.ts | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 03d0dda7f..c7f10142c 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -3,17 +3,21 @@ Convert an object with `readonly` keys into a mutable object. Inverse of `Readon This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509). +@see [SetMutable](source/set-mutable.d.ts) + @example ``` import {Mutable} from 'type-fest'; type Foo = { readonly a: number; - readonly b: string; + readonly b: readonly string[]; }; -const mutableFoo: Mutable = {a: 1, b: '2'}; +const mutableFoo: Mutable = {a: 1, b: ['2']}; mutableFoo.a = 3; +mutableFoo.b[0] = '3'; // -> Results in TypeError – Index signature in type 'readonly string[]' only permits reading.ts(2542). +mutableFoo.b = ['3']; ``` */ export type Mutable = { diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts index 23e9c7419..18e4b706d 100644 --- a/source/set-mutable.d.ts +++ b/source/set-mutable.d.ts @@ -6,25 +6,27 @@ Create a type that converts the given keys from `readonly` to mutable. The remai Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are mutable. +@see [Mutable](source/mutable.d.ts) + @example ``` import {SetMutable} from 'type-fest'; type Foo = { readonly a: number; - b: string; + b: readonly string[]; readonly c: boolean; } type SomeMutable = SetMutable; // type SomeMutable = { // readonly a: number; -// b: string; // Was already mutable and still is. +// b: readonly string[]; // Was already mutable and still is, type of the property remains unaffected. // c: boolean; // Is now mutable. // } ``` */ -export type SetMutable = +export type SetMutable = // Pick just the keys that are not mutable from the base type. Except & // Pick the keys that should be mutable from the base type and make them mutable. diff --git a/source/set-optional.d.ts b/source/set-optional.d.ts index 35398992b..a5dc1bfdb 100644 --- a/source/set-optional.d.ts +++ b/source/set-optional.d.ts @@ -23,7 +23,7 @@ type SomeOptional = SetOptional; // } ``` */ -export type SetOptional = +export type SetOptional = // Pick just the keys that are not optional from the base type. Except & // Pick the keys that should be optional from the base type and make them optional. diff --git a/source/set-required.d.ts b/source/set-required.d.ts index 0a7233077..85a5a07a0 100644 --- a/source/set-required.d.ts +++ b/source/set-required.d.ts @@ -23,7 +23,7 @@ type SomeRequired = SetRequired; // } ``` */ -export type SetRequired = +export type SetRequired = // Pick just the keys that are not required from the base type. Except & // Pick the keys that should be required from the base type and make them required. From 9590e53d82f61978679d8c3dbd3d96a54965c1ad Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 1 Dec 2020 15:34:51 +0700 Subject: [PATCH 07/25] Update set-mutable.d.ts --- source/set-mutable.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts index 18e4b706d..e8378bb97 100644 --- a/source/set-mutable.d.ts +++ b/source/set-mutable.d.ts @@ -6,7 +6,7 @@ Create a type that converts the given keys from `readonly` to mutable. The remai Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are mutable. -@see [Mutable](source/mutable.d.ts) +@see [`Mutable`](source/mutable.d.ts) @example ``` From b350c30d7828b621b854244d8708f948b3224fdb Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Tue, 1 Dec 2020 15:36:42 +0700 Subject: [PATCH 08/25] Update mutable.d.ts --- source/mutable.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index c7f10142c..1640f93e7 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -3,7 +3,7 @@ Convert an object with `readonly` keys into a mutable object. Inverse of `Readon This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509). -@see [SetMutable](source/set-mutable.d.ts) +@see [`SetMutable`](source/set-mutable.d.ts) @example ``` @@ -16,7 +16,7 @@ type Foo = { const mutableFoo: Mutable = {a: 1, b: ['2']}; mutableFoo.a = 3; -mutableFoo.b[0] = '3'; // -> Results in TypeError – Index signature in type 'readonly string[]' only permits reading.ts(2542). +mutableFoo.b[0] = '3'; //=> Index signature in type 'readonly string[]' only permits reading.ts(2542). mutableFoo.b = ['3']; ``` */ From dfeff63b872e53b208464299ec6ef6ae8009d5e3 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Tue, 1 Dec 2020 12:47:39 +0100 Subject: [PATCH 09/25] Clarify relationships --- source/mutable.d.ts | 2 +- source/set-mutable.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 1640f93e7..9dce4fefc 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -3,7 +3,7 @@ Convert an object with `readonly` keys into a mutable object. Inverse of `Readon This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509). -@see [`SetMutable`](source/set-mutable.d.ts) +@see [`SetMutable`](source/set-mutable.d.ts) – a type that can selectively set some keys as mutable. @example ``` diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts index e8378bb97..454037dc8 100644 --- a/source/set-mutable.d.ts +++ b/source/set-mutable.d.ts @@ -6,7 +6,7 @@ Create a type that converts the given keys from `readonly` to mutable. The remai Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are mutable. -@see [`Mutable`](source/mutable.d.ts) +@see [`Mutable`](source/mutable.d.ts) - a type that sets all (not selectively) keys as mutable. @example ``` From 103c63fdf59c3084cbc5189f742c8953ca663e17 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Tue, 1 Dec 2020 13:59:45 +0100 Subject: [PATCH 10/25] Update source/set-mutable.d.ts Co-authored-by: Pelle Wessman --- source/set-mutable.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts index 454037dc8..d65466849 100644 --- a/source/set-mutable.d.ts +++ b/source/set-mutable.d.ts @@ -31,7 +31,7 @@ export type SetMutable = Except & // Pick the keys that should be mutable from the base type and make them mutable. Mutable> extends - // If `InferredType` extends the previous, then for each key, use the inferred type key. + // Assigns the combined values to `InferredType` for easy reference infer InferredType ? {[KeyType in keyof InferredType]: InferredType[KeyType]} : never; From b5fde12146c0074f2b61f74093d4368fd041dfdd Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Tue, 1 Dec 2020 14:12:37 +0100 Subject: [PATCH 11/25] Update wrong comments --- source/mutable.d.ts | 3 ++- test-d/set-mutable.ts | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 9dce4fefc..8fab2a5ee 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -16,7 +16,8 @@ type Foo = { const mutableFoo: Mutable = {a: 1, b: ['2']}; mutableFoo.a = 3; -mutableFoo.b[0] = '3'; //=> Index signature in type 'readonly string[]' only permits reading.ts(2542). +// Type of the property remains unaffected +mutableFoo.b[0] = '3'; // -> Error: Index signature in type 'readonly string[]' only permits reading.ts(2542). mutableFoo.b = ['3']; ``` */ diff --git a/test-d/set-mutable.ts b/test-d/set-mutable.ts index cd1d72413..e743ee2b7 100644 --- a/test-d/set-mutable.ts +++ b/test-d/set-mutable.ts @@ -1,18 +1,18 @@ import {expectType, expectError} from 'tsd'; import {SetMutable} from '..'; -// Update one required and one optional to required. +// Update one mutable and one readonly to mutable, leaving one property unaffected. declare const variation1: SetMutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; expectType<{readonly a: number; b: string; c: boolean}>(variation1); -// Update two optional to required. +// Update two readonly to mutable, leaving one property unaffected. declare const variation2: SetMutable<{readonly a: number; readonly b: string; readonly c: boolean}, 'a' | 'b'>; expectType<{a: number; b: string; readonly c: boolean}>(variation2); -// Three required remain required. +// Three mutable remain mutable. declare const variation3: SetMutable<{a: number; b: string; c: boolean}, 'a' | 'b' | 'c'>; expectType<{a: number; b: string; c: boolean}>(variation3); -// Fail if type changes even if optional is right. +// Check if type changes raise an error even if readonly and mutable are applied correctly. declare const variation4: SetMutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; expectError<{readonly a: boolean; b: string; c: boolean}>(variation4); From b7b495b42561c2fdc65cdfa7926bb8ed99580af6 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Tue, 1 Dec 2020 15:11:39 +0100 Subject: [PATCH 12/25] Update source/mutable.d.ts Co-authored-by: Pelle Wessman --- source/mutable.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 8fab2a5ee..7180e1d7e 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -11,7 +11,7 @@ import {Mutable} from 'type-fest'; type Foo = { readonly a: number; - readonly b: readonly string[]; + readonly b: readonly string[]; // To show that only the mutability status of the properties, not their values, are affected }; const mutableFoo: Mutable = {a: 1, b: ['2']}; From 02b440bc5aab7650872d9b2e1cb9f7bbdd069e33 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Tue, 1 Dec 2020 15:12:10 +0100 Subject: [PATCH 13/25] Update source/mutable.d.ts Co-authored-by: Pelle Wessman --- source/mutable.d.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 7180e1d7e..cd21541d2 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -16,9 +16,8 @@ type Foo = { const mutableFoo: Mutable = {a: 1, b: ['2']}; mutableFoo.a = 3; -// Type of the property remains unaffected -mutableFoo.b[0] = '3'; // -> Error: Index signature in type 'readonly string[]' only permits reading.ts(2542). -mutableFoo.b = ['3']; +mutableFoo.b[0] = 'new value'; // -> Will still fail as the value of property "b" is still a readonly type +mutableFoo.b = ['something']; // -> Will work as the "b" property itself is no longer readonly ``` */ export type Mutable = { From 1af6d4a2cb0982ab76f611943d5f9c47a49d7e74 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Wed, 2 Dec 2020 13:27:58 +0100 Subject: [PATCH 14/25] Use `Simplify` type for flattening `Set-` types output --- source/set-mutable.d.ts | 15 +++++++-------- source/set-optional.d.ts | 15 +++++++-------- source/set-required.d.ts | 15 +++++++-------- source/simplify.d.ts | 2 ++ 4 files changed, 23 insertions(+), 24 deletions(-) create mode 100644 source/simplify.d.ts diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts index d65466849..7c4950168 100644 --- a/source/set-mutable.d.ts +++ b/source/set-mutable.d.ts @@ -1,5 +1,6 @@ import {Except} from './except'; import {Mutable} from './mutable'; +import {Simplify} from './simplify'; /** Create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is. @@ -27,11 +28,9 @@ type SomeMutable = SetMutable; ``` */ export type SetMutable = - // Pick just the keys that are not mutable from the base type. - Except & - // Pick the keys that should be mutable from the base type and make them mutable. - Mutable> extends - // Assigns the combined values to `InferredType` for easy reference - infer InferredType - ? {[KeyType in keyof InferredType]: InferredType[KeyType]} - : never; + Simplify< + // Pick just the keys that are not mutable from the base type. + Except & + // Pick the keys that should be mutable from the base type and make them mutable. + Mutable> + >; diff --git a/source/set-optional.d.ts b/source/set-optional.d.ts index a5dc1bfdb..ebaf09819 100644 --- a/source/set-optional.d.ts +++ b/source/set-optional.d.ts @@ -1,4 +1,5 @@ import {Except} from './except'; +import {Simplify} from './simplify'; /** Create a type that makes the given keys optional. The remaining keys are kept as is. The sister of the `SetRequired` type. @@ -24,11 +25,9 @@ type SomeOptional = SetOptional; ``` */ export type SetOptional = - // Pick just the keys that are not optional from the base type. - Except & - // Pick the keys that should be optional from the base type and make them optional. - Partial> extends - // If `InferredType` extends the previous, then for each key, use the inferred type key. - infer InferredType - ? {[KeyType in keyof InferredType]: InferredType[KeyType]} - : never; + Simplify< + // Pick just the keys that are readonly from the base type. + Except & + // Pick the keys that should be mutable from the base type and make them mutable. + Partial> + >; diff --git a/source/set-required.d.ts b/source/set-required.d.ts index 85a5a07a0..ab8593eb5 100644 --- a/source/set-required.d.ts +++ b/source/set-required.d.ts @@ -1,4 +1,5 @@ import {Except} from './except'; +import {Simplify} from './simplify'; /** Create a type that makes the given keys required. The remaining keys are kept as is. The sister of the `SetOptional` type. @@ -24,11 +25,9 @@ type SomeRequired = SetRequired; ``` */ export type SetRequired = - // Pick just the keys that are not required from the base type. - Except & - // Pick the keys that should be required from the base type and make them required. - Required> extends - // If `InferredType` extends the previous, then for each key, use the inferred type key. - infer InferredType - ? {[KeyType in keyof InferredType]: InferredType[KeyType]} - : never; + Simplify< + // Pick just the keys that are optional from the base type. + Except & + // Pick the keys that should be required from the base type and make them required. + Required> + >; diff --git a/source/simplify.d.ts b/source/simplify.d.ts new file mode 100644 index 000000000..5e1e403ec --- /dev/null +++ b/source/simplify.d.ts @@ -0,0 +1,2 @@ +/** Flattens the type output for ease of reference. */ +export type Simplify = {[KeyType in keyof T]: T[KeyType]}; From 8a4160507c0733e70bf2e06d564dd98d56515484 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Wed, 2 Dec 2020 13:49:21 +0100 Subject: [PATCH 15/25] Mege `SetMutable` with `Mutable` --- base.d.ts | 1 - readme.md | 3 +-- source/mutable.d.ts | 25 ++++++++++++++++++------- source/set-mutable.d.ts | 36 ------------------------------------ test-d/mutable.ts | 17 +++++++++++++++++ 5 files changed, 36 insertions(+), 46 deletions(-) delete mode 100644 source/set-mutable.d.ts diff --git a/base.d.ts b/base.d.ts index d478d1fb7..9005ef9fc 100644 --- a/base.d.ts +++ b/base.d.ts @@ -18,7 +18,6 @@ export {Promisable} from './source/promisable'; export {Opaque} from './source/opaque'; export {SetOptional} from './source/set-optional'; export {SetRequired} from './source/set-required'; -export {SetMutable} from './source/set-mutable'; export {ValueOf} from './source/value-of'; export {PromiseValue} from './source/promise-value'; export {AsyncReturnType} from './source/async-return-type'; diff --git a/readme.md b/readme.md index 5d14affbb..e8b2bdf84 100644 --- a/readme.md +++ b/readme.md @@ -61,7 +61,7 @@ Click the type names for complete docs. ### Utilities - [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). -- [`Mutable`](source/mutable.d.ts) - Convert an object with `readonly` keys into a mutable object. The inverse of `Readonly`. +- [`Mutable`](source/mutable.d.ts) - Convert an object with `readonly` keys into a mutable object. The inverse of `Readonly`. Alternatively create a type that converts the given keys from `readonly` to mutable. - [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type. - [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys. - [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys. @@ -73,7 +73,6 @@ Click the type names for complete docs. - [`Opaque`](source/opaque.d.ts) - Create an [opaque type](https://codemix.com/opaque-types-in-javascript/). - [`SetOptional`](source/set-optional.d.ts) - Create a type that makes the given keys optional. - [`SetRequired`](source/set-required.d.ts) - Create a type that makes the given keys required. -- [`SetMutable`](source/set-mutable.d.ts) - Create a type that converts the given keys from `readonly` to mutable. - [`ValueOf`](source/value-of.d.ts) - Create a union of the given object's values, and optionally specify which keys to get the values from. - [`PromiseValue`](source/promise-value.d.ts) - Returns the type that is wrapped inside a `Promise`. - [`AsyncReturnType`](source/async-return-type.d.ts) - Unwrap the return type of a function that returns a `Promise`. diff --git a/source/mutable.d.ts b/source/mutable.d.ts index cd21541d2..0fa9c767c 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -1,9 +1,9 @@ /** Convert an object with `readonly` keys into a mutable object. Inverse of `Readonly`. +Alternatively create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is. This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509). - -@see [`SetMutable`](source/set-mutable.d.ts) – a type that can selectively set some keys as mutable. +Or to define a single model where the only thing that changes is whether or not some of the keys are mutable. @example ``` @@ -11,16 +11,27 @@ import {Mutable} from 'type-fest'; type Foo = { readonly a: number; - readonly b: readonly string[]; // To show that only the mutability status of the properties, not their values, are affected + readonly b: readonly string[]; // To show that only the mutability status of the properties, not their values, are affected + readonly c: boolean; }; const mutableFoo: Mutable = {a: 1, b: ['2']}; mutableFoo.a = 3; mutableFoo.b[0] = 'new value'; // -> Will still fail as the value of property "b" is still a readonly type mutableFoo.b = ['something']; // -> Will work as the "b" property itself is no longer readonly + +type SomeMutable = Mutable; +// type SomeMutable = { +// readonly a: number; +// b: readonly string[]; // Is now mutable, type of the property remains unaffected. +// c: boolean; // Is now mutable. +// } ``` */ -export type Mutable = { - // For each `Key` in the keys of `ObjectType`, make a mapped type by removing the `readonly` modifier from the key. - -readonly [KeyType in keyof ObjectType]: ObjectType[KeyType]; -}; +export type Mutable = + Simplify< + // Pick just the keys that are not mutable from the base type. + Except & + // Pick the keys that should be mutable from the base type and make them mutable by removing the `readonly` modifier from the key. + {-readonly [KeyType in keyof Pick]: Pick[KeyType]} + >; diff --git a/source/set-mutable.d.ts b/source/set-mutable.d.ts deleted file mode 100644 index 7c4950168..000000000 --- a/source/set-mutable.d.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {Except} from './except'; -import {Mutable} from './mutable'; -import {Simplify} from './simplify'; - -/** -Create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is. - -Use-case: You want to define a single model where the only thing that changes is whether or not some of the keys are mutable. - -@see [`Mutable`](source/mutable.d.ts) - a type that sets all (not selectively) keys as mutable. - -@example -``` -import {SetMutable} from 'type-fest'; - -type Foo = { - readonly a: number; - b: readonly string[]; - readonly c: boolean; -} - -type SomeMutable = SetMutable; -// type SomeMutable = { -// readonly a: number; -// b: readonly string[]; // Was already mutable and still is, type of the property remains unaffected. -// c: boolean; // Is now mutable. -// } -``` -*/ -export type SetMutable = - Simplify< - // Pick just the keys that are not mutable from the base type. - Except & - // Pick the keys that should be mutable from the base type and make them mutable. - Mutable> - >; diff --git a/test-d/mutable.ts b/test-d/mutable.ts index f6ddf494b..a83374dcf 100644 --- a/test-d/mutable.ts +++ b/test-d/mutable.ts @@ -1,3 +1,4 @@ +import {expectType, expectError} from 'tsd'; import {Mutable} from '..'; type Foo = { @@ -9,3 +10,19 @@ const ab: Mutable = {a: 1, b: '2'}; ab.a = 2; const ab2: Mutable> = ab; ab2.a = 2; + +// Update one mutable and one readonly to mutable, leaving one property unaffected. +declare const variation1: Mutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; +expectType<{readonly a: number; b: string; c: boolean}>(variation1); + +// Update two readonly to mutable, leaving one property unaffected. +declare const variation2: Mutable<{readonly a: number; readonly b: string; readonly c: boolean}, 'a' | 'b'>; +expectType<{a: number; b: string; readonly c: boolean}>(variation2); + +// Three mutable remain mutable. +declare const variation3: Mutable<{a: number; b: string; c: boolean}, 'a' | 'b' | 'c'>; +expectType<{a: number; b: string; c: boolean}>(variation3); + +// Check if type changes raise an error even if readonly and mutable are applied correctly. +declare const variation4: Mutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; +expectError<{readonly a: boolean; b: string; c: boolean}>(variation4); From 50f5447a8006f23adefd0a16ab1e9e151be7c935 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 16 Dec 2020 14:46:22 +0700 Subject: [PATCH 16/25] Update simplify.d.ts --- source/simplify.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/simplify.d.ts b/source/simplify.d.ts index 5e1e403ec..5a65cdfbf 100644 --- a/source/simplify.d.ts +++ b/source/simplify.d.ts @@ -1,2 +1,4 @@ -/** Flattens the type output for ease of reference. */ +/** +Flatten the type output for ease of reference. +*/ export type Simplify = {[KeyType in keyof T]: T[KeyType]}; From d953a14c9cf381b7bc9244c80903e0a020f41e25 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Wed, 16 Dec 2020 14:52:16 +0700 Subject: [PATCH 17/25] Update mutable.d.ts --- source/mutable.d.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 0fa9c767c..0be83d8e8 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -11,20 +11,20 @@ import {Mutable} from 'type-fest'; type Foo = { readonly a: number; - readonly b: readonly string[]; // To show that only the mutability status of the properties, not their values, are affected - readonly c: boolean; + readonly b: readonly string[]; // To show that only the mutability status of the properties, not their values, are affected. + readonly c: boolean; }; const mutableFoo: Mutable = {a: 1, b: ['2']}; mutableFoo.a = 3; -mutableFoo.b[0] = 'new value'; // -> Will still fail as the value of property "b" is still a readonly type -mutableFoo.b = ['something']; // -> Will work as the "b" property itself is no longer readonly +mutableFoo.b[0] = 'new value'; // Will still fail as the value of property "b" is still a readonly type. +mutableFoo.b = ['something']; // Will work as the "b" property itself is no longer readonly. type SomeMutable = Mutable; // type SomeMutable = { // readonly a: number; -// b: readonly string[]; // Is now mutable, type of the property remains unaffected. -// c: boolean; // Is now mutable. +// b: readonly string[]; // It's now mutable. The type of the property remains unaffected. +// c: boolean; // It's now mutable. // } ``` */ From 2a43c510348755acd05ba2c71b3e73bf83813b45 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 17 Dec 2020 19:02:08 +0100 Subject: [PATCH 18/25] Remove obsolete test file --- test-d/set-mutable.ts | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 test-d/set-mutable.ts diff --git a/test-d/set-mutable.ts b/test-d/set-mutable.ts deleted file mode 100644 index e743ee2b7..000000000 --- a/test-d/set-mutable.ts +++ /dev/null @@ -1,18 +0,0 @@ -import {expectType, expectError} from 'tsd'; -import {SetMutable} from '..'; - -// Update one mutable and one readonly to mutable, leaving one property unaffected. -declare const variation1: SetMutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; -expectType<{readonly a: number; b: string; c: boolean}>(variation1); - -// Update two readonly to mutable, leaving one property unaffected. -declare const variation2: SetMutable<{readonly a: number; readonly b: string; readonly c: boolean}, 'a' | 'b'>; -expectType<{a: number; b: string; readonly c: boolean}>(variation2); - -// Three mutable remain mutable. -declare const variation3: SetMutable<{a: number; b: string; c: boolean}, 'a' | 'b' | 'c'>; -expectType<{a: number; b: string; c: boolean}>(variation3); - -// Check if type changes raise an error even if readonly and mutable are applied correctly. -declare const variation4: SetMutable<{readonly a: number; b: string; readonly c: boolean}, 'b' | 'c'>; -expectError<{readonly a: boolean; b: string; c: boolean}>(variation4); From 4de51438aa99c5612bca118fc5f6c3805077ba92 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 17 Dec 2020 19:08:26 +0100 Subject: [PATCH 19/25] Improve documentation --- readme.md | 2 +- source/mutable.d.ts | 3 +-- source/simplify.d.ts | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index e8b2bdf84..0da5a0825 100644 --- a/readme.md +++ b/readme.md @@ -61,7 +61,7 @@ Click the type names for complete docs. ### Utilities - [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). -- [`Mutable`](source/mutable.d.ts) - Convert an object with `readonly` keys into a mutable object. The inverse of `Readonly`. Alternatively create a type that converts the given keys from `readonly` to mutable. +- [`Mutable`](source/mutable.d.ts) - Convert an object with `readonly` keys into a mutable object. The inverse of `Readonly`. Alternatively creates a type that converts the given keys from `readonly` to mutable and the remaining keys are kept as is, as opposed to converting all keys to mutable. - [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type. - [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys. - [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys. diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 0fa9c767c..a092f4cb7 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -2,8 +2,7 @@ Convert an object with `readonly` keys into a mutable object. Inverse of `Readonly`. Alternatively create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is. -This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509). -Or to define a single model where the only thing that changes is whether or not some of the keys are mutable. +This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509) or to define a single model where the only thing that changes is whether or not some of the keys are mutable. @example ``` diff --git a/source/simplify.d.ts b/source/simplify.d.ts index 5e1e403ec..dbaadbc31 100644 --- a/source/simplify.d.ts +++ b/source/simplify.d.ts @@ -1,2 +1,2 @@ -/** Flattens the type output for ease of reference. */ +/** Flattens the type output to improve type hints shown in editors. */ export type Simplify = {[KeyType in keyof T]: T[KeyType]}; From f6edcd150d514ff34d498584df3da88b79090360 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 17 Dec 2020 22:58:00 +0100 Subject: [PATCH 20/25] Update source/simplify.d.ts Co-authored-by: Sindre Sorhus --- source/simplify.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/simplify.d.ts b/source/simplify.d.ts index 66b5edc2f..5e067c24e 100644 --- a/source/simplify.d.ts +++ b/source/simplify.d.ts @@ -1,4 +1,4 @@ /** -Flattens the type output to improve type hints shown in editors. +Flatten the type output to improve type hints shown in editors. */ export type Simplify = {[KeyType in keyof T]: T[KeyType]}; From c93f096f230106c78bd907fadfd0e65725778de6 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 17 Dec 2020 22:58:15 +0100 Subject: [PATCH 21/25] Update source/mutable.d.ts Co-authored-by: Sindre Sorhus --- source/mutable.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index fa753ac20..410d53f8f 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -2,7 +2,7 @@ Convert an object with `readonly` keys into a mutable object. Inverse of `Readonly`. Alternatively create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is. -This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), and [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509) or to define a single model where the only thing that changes is whether or not some of the keys are mutable. +This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509), or to define a single model where the only thing that changes is whether or not some of the keys are mutable. @example ``` From def1d3f49d59578718d73a45c3e4a3d8cc53f6d5 Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Thu, 17 Dec 2020 23:01:58 +0100 Subject: [PATCH 22/25] Improve documentation --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 0da5a0825..1c466bb33 100644 --- a/readme.md +++ b/readme.md @@ -61,7 +61,7 @@ Click the type names for complete docs. ### Utilities - [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). -- [`Mutable`](source/mutable.d.ts) - Convert an object with `readonly` keys into a mutable object. The inverse of `Readonly`. Alternatively creates a type that converts the given keys from `readonly` to mutable and the remaining keys are kept as is, as opposed to converting all keys to mutable. +- [`Mutable`](source/mutable.d.ts) - Strip `readonly` from all or some of an object's keys. The inverse of `Readonly`. - [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type. - [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys. - [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys. From c8cc662f564c36a74d0e430717220a387bedd3de Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Sun, 20 Dec 2020 11:58:06 +0100 Subject: [PATCH 23/25] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 1c466bb33..49aa888be 100644 --- a/readme.md +++ b/readme.md @@ -61,7 +61,7 @@ Click the type names for complete docs. ### Utilities - [`Except`](source/except.d.ts) - Create a type from an object type without certain keys. This is a stricter version of [`Omit`](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type). -- [`Mutable`](source/mutable.d.ts) - Strip `readonly` from all or some of an object's keys. The inverse of `Readonly`. +- [`Mutable`](source/mutable.d.ts) - Create a type that strips `readonly` from all or some of an object's keys. The inverse of `Readonly`. - [`Merge`](source/merge.d.ts) - Merge two types into a new type. Keys of the second type overrides keys of the first type. - [`MergeExclusive`](source/merge-exclusive.d.ts) - Create a type that has mutually exclusive keys. - [`RequireAtLeastOne`](source/require-at-least-one.d.ts) - Create a type that requires at least one of the given keys. From 87a78c73905bd013def0c557ead0a6e936ea31d3 Mon Sep 17 00:00:00 2001 From: Sindre Sorhus Date: Sat, 26 Dec 2020 17:48:17 +0700 Subject: [PATCH 24/25] Update mutable.d.ts --- source/mutable.d.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 410d53f8f..18d4a2269 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -1,6 +1,5 @@ /** -Convert an object with `readonly` keys into a mutable object. Inverse of `Readonly`. -Alternatively create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is. +Create a type that strips `readonly` from all or some of an object's keys. Inverse of `Readonly`. This can be used to [store and mutate options within a class](https://github.com/sindresorhus/pageres/blob/4a5d05fca19a5fbd2f53842cbf3eb7b1b63bddd2/source/index.ts#L72), [edit `readonly` objects within tests](https://stackoverflow.com/questions/50703834), [construct a `readonly` object within a function](https://github.com/Microsoft/TypeScript/issues/24509), or to define a single model where the only thing that changes is whether or not some of the keys are mutable. From 55c60e2d9b55d8116e0d93521a8ed47717a7c46a Mon Sep 17 00:00:00 2001 From: Kai Niedziela Date: Sat, 26 Dec 2020 14:57:21 +0100 Subject: [PATCH 25/25] Import utility types into Mutable --- source/mutable.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/mutable.d.ts b/source/mutable.d.ts index 410d53f8f..23b407d7d 100644 --- a/source/mutable.d.ts +++ b/source/mutable.d.ts @@ -1,3 +1,6 @@ +import {Except} from './except'; +import {Simplify} from './simplify'; + /** Convert an object with `readonly` keys into a mutable object. Inverse of `Readonly`. Alternatively create a type that converts the given keys from `readonly` to mutable. The remaining keys are kept as is.