From 1a69e6379da58ab1fb4546f11525929f2d2f100e Mon Sep 17 00:00:00 2001 From: Johann Cooper Date: Mon, 22 Aug 2022 10:03:48 -0700 Subject: [PATCH] Add `SetNonNullable` type (#431) --- index.d.ts | 1 + readme.md | 1 + source/set-non-nullable.d.ts | 35 +++++++++++++++++++++++++++++++++++ test-d/set-non-nullable.ts | 18 ++++++++++++++++++ 4 files changed, 55 insertions(+) create mode 100644 source/set-non-nullable.d.ts create mode 100644 test-d/set-non-nullable.ts diff --git a/index.d.ts b/index.d.ts index a8bdc753b..ee20662e4 100644 --- a/index.d.ts +++ b/index.d.ts @@ -23,6 +23,7 @@ export {Opaque, UnwrapOpaque} from './source/opaque'; export {InvariantOf} from './source/invariant-of'; export {SetOptional} from './source/set-optional'; export {SetRequired} from './source/set-required'; +export {SetNonNullable} from './source/set-non-nullable'; 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 d1dc3c453..0d310aad7 100644 --- a/readme.md +++ b/readme.md @@ -142,6 +142,7 @@ Click the type names for complete docs. - [`InvariantOf`](source/invariant-of.d.ts) - Create an [invariant type](https://basarat.gitbook.io/typescript/type-system/type-compatibility#footnote-invariance), which is a type that does not accept supertypes and subtypes. - [`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. +- [`SetNonNullable`](source/set-non-nullable.d.ts) - Create a type that makes the given keys non-nullable. - [`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. - [`ConditionalKeys`](source/conditional-keys.d.ts) - Extract keys from a shape where values extend the given `Condition` type. - [`ConditionalPick`](source/conditional-pick.d.ts) - Like `Pick` except it selects properties from a shape where the values extend the given `Condition` type. diff --git a/source/set-non-nullable.d.ts b/source/set-non-nullable.d.ts new file mode 100644 index 000000000..cea613c56 --- /dev/null +++ b/source/set-non-nullable.d.ts @@ -0,0 +1,35 @@ +import type {Except} from './except'; +import type {Simplify} from './simplify'; + +/** +Create a type that makes the given keys non-nullable. 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 non-nullable. + +@example +``` +import type {SetNonNullable} from 'type-fest'; + +type Foo = { + a: number; + b: string | undefined; + c?: boolean | null; +} + +type SomeNonNullable = SetNonNullable; +// type SomeNonNullable = { +// a: number; +// b: string; // Can no longer be undefined. +// c?: boolean; // Can no longer be null, but is still optional. +// } +``` + +@category Object +*/ +export type SetNonNullable = + Simplify< + // Pick just the keys that are readonly from the base type. + Except & + // Pick the keys that should be non-nullable from the base type and make them non-nullable. + {[Key in Keys]: NonNullable} + >; diff --git a/test-d/set-non-nullable.ts b/test-d/set-non-nullable.ts new file mode 100644 index 000000000..b17c3ddf3 --- /dev/null +++ b/test-d/set-non-nullable.ts @@ -0,0 +1,18 @@ +import {expectType, expectError} from 'tsd'; +import type {SetNonNullable} from '../index'; + +// Update one possibly undefined key and one possibly null key to non-nullable. +declare const variation1: SetNonNullable<{a: number; b: string | undefined; c: boolean | null}, 'b' | 'c'>; +expectType<{a: number; b: string; c: boolean}>(variation1); + +// Update a key that is possibly null or undefined. +declare const variation2: SetNonNullable<{a: number; b: string | null | undefined}, 'b'>; +expectType<{a: number; b: string}>(variation2); + +// Update an optional key. +declare const variation3: SetNonNullable<{a: number; b?: string | undefined}, 'b'>; +expectType<{a: number; b?: string}>(variation3); + +// Fail if type changes even if non-nullable is right. +declare const variation4: SetNonNullable<{a: number; b: string | undefined}, 'b'>; +expectError<{a: string; b: string}>(variation4);