Skip to content

Commit d607cdc

Browse files
authored
feat: option to generate default TypeScript-like name for some methods (#98)
Use `name: null` as option with `withOptional`, `withRequired` or `mergeWith` to force generating a default TypeScript-like type-name instead of reusing the custom name of the original type.
1 parent e05560f commit d607cdc

File tree

8 files changed

+65
-32
lines changed

8 files changed

+65
-32
lines changed

etc/types.api.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ export type int = The<typeof int>;
140140
// @public (undocumented)
141141
export const int: Type<Branded<number, 'int'>, NumberTypeConfig>;
142142

143-
// @public (undocumented)
143+
// @public
144144
export interface InterfaceMergeOptions {
145-
name?: string;
145+
name?: string | null;
146146
omitParsers?: true;
147147
omitValidations?: true;
148148
}

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const config = {
1313
coverageThreshold: {
1414
global: {
1515
statements: -3,
16-
branches: -15,
16+
branches: -14,
1717
functions: -1,
1818
lines: 100,
1919
},

markdown/types.interfacemergeoptions.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
## InterfaceMergeOptions interface
66

7+
Options for [InterfaceType.withOptional()](./types.interfacetype.withoptional.md)<!-- -->, [InterfaceType.withRequired()](./types.interfacetype.withrequired.md) and [InterfaceType.mergeWith()](./types.interfacetype.mergewith.md)<!-- -->.
8+
79
**Signature:**
810

911
```typescript
@@ -12,8 +14,8 @@ interface InterfaceMergeOptions
1214

1315
## Properties
1416

15-
| Property | Modifiers | Type | Description |
16-
| -------------------------------------------------------------------- | --------- | ------ | -------------------------------------------------------------------------------------------------------- |
17-
| [name?](./types.interfacemergeoptions.name.md) | | string | _(Optional)_ The optional name for the type, uses a default TypeScript-like name if no name is given. |
18-
| [omitParsers?](./types.interfacemergeoptions.omitparsers.md) | | true | _(Optional)_ Suppress the error about existing custom parsers on one of the types that is being merged. |
19-
| [omitValidations?](./types.interfacemergeoptions.omitvalidations.md) | | true | _(Optional)_ When set, do not apply the custom validations from the base types onto the new merged type. |
17+
| Property | Modifiers | Type | Description |
18+
| -------------------------------------------------------------------- | --------- | -------------- | ---------------------------------------------------------------------------------------------------------------- |
19+
| [name?](./types.interfacemergeoptions.name.md) | | string \| null | _(Optional)_ The optional name for the new type, or <code>null</code> to force a generated TypeScript-like name. |
20+
| [omitParsers?](./types.interfacemergeoptions.omitparsers.md) | | true | _(Optional)_ Suppress the error about existing custom parsers on one of the types that is being merged. |
21+
| [omitValidations?](./types.interfacemergeoptions.omitvalidations.md) | | true | _(Optional)_ When set, do not apply the custom validations from the base types onto the new merged type. |

markdown/types.interfacemergeoptions.name.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44

55
## InterfaceMergeOptions.name property
66

7-
The optional name for the type, uses a default TypeScript-like name if no name is given.
7+
The optional name for the new type, or `null` to force a generated TypeScript-like name.
88

99
**Signature:**
1010

1111
```typescript
12-
name?: string;
12+
name?: string | null;
1313
```
14+
15+
## Remarks
16+
17+
When omitted, it will follow the name of original type (on the left). It will either use the custom name of that type or generate a new default TypeScript-like name if the type did not have a custom name.
18+
19+
Use this `name` setting with a `string` to provide a new custom name or use `null` to force a generated TypeScript-like name, even if the original type has a custom name.

markdown/types.md

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,22 @@ Runtime type-validation with derived TypeScript types.
5252

5353
## Interfaces
5454

55-
| Interface | Description |
56-
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
57-
| [ArrayTypeConfig](./types.arraytypeconfig.md) | Configuration of additional checks on array types. |
58-
| [Failure](./types.failure.md) | A failed validation result. |
59-
| [InterfaceMergeOptions](./types.interfacemergeoptions.md) | |
60-
| [InterfaceTypeOptions](./types.interfacetypeoptions.md) | Options for [object()](./types.object.md)<!-- -->. |
61-
| [InterfaceTypeOptionsWithPartial](./types.interfacetypeoptionswithpartial.md) | |
62-
| [LengthChecksConfig](./types.lengthchecksconfig.md) | |
63-
| [ParserOptions](./types.parseroptions.md) | Options that can be passed to [BaseTypeImpl.withParser()](./types.basetypeimpl.withparser.md)<!-- -->. |
64-
| [SimpleTypeOptions](./types.simpletypeoptions.md) | |
65-
| [StringTypeConfig](./types.stringtypeconfig.md) | Configuration of additional checks on string types. |
66-
| [Success](./types.success.md) | A successful validation result. |
67-
| [TypedPropertyInformation](./types.typedpropertyinformation.md) | Interface that provides more detailed type-information about the <code>props</code> and <code>propsInfo</code> properties of the validator. |
68-
| [TypeLink](./types.typelink.md) | An object that has an associated TypeScript type. |
69-
| [ValidationOptions](./types.validationoptions.md) | |
70-
| [Visitor](./types.visitor.md) | Interface for a visitor that is accepted by all types (classic visitor-pattern). |
55+
| Interface | Description |
56+
| ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
57+
| [ArrayTypeConfig](./types.arraytypeconfig.md) | Configuration of additional checks on array types. |
58+
| [Failure](./types.failure.md) | A failed validation result. |
59+
| [InterfaceMergeOptions](./types.interfacemergeoptions.md) | Options for [InterfaceType.withOptional()](./types.interfacetype.withoptional.md)<!-- -->, [InterfaceType.withRequired()](./types.interfacetype.withrequired.md) and [InterfaceType.mergeWith()](./types.interfacetype.mergewith.md)<!-- -->. |
60+
| [InterfaceTypeOptions](./types.interfacetypeoptions.md) | Options for [object()](./types.object.md)<!-- -->. |
61+
| [InterfaceTypeOptionsWithPartial](./types.interfacetypeoptionswithpartial.md) | |
62+
| [LengthChecksConfig](./types.lengthchecksconfig.md) | |
63+
| [ParserOptions](./types.parseroptions.md) | Options that can be passed to [BaseTypeImpl.withParser()](./types.basetypeimpl.withparser.md)<!-- -->. |
64+
| [SimpleTypeOptions](./types.simpletypeoptions.md) | |
65+
| [StringTypeConfig](./types.stringtypeconfig.md) | Configuration of additional checks on string types. |
66+
| [Success](./types.success.md) | A successful validation result. |
67+
| [TypedPropertyInformation](./types.typedpropertyinformation.md) | Interface that provides more detailed type-information about the <code>props</code> and <code>propsInfo</code> properties of the validator. |
68+
| [TypeLink](./types.typelink.md) | An object that has an associated TypeScript type. |
69+
| [ValidationOptions](./types.validationoptions.md) | |
70+
| [Visitor](./types.visitor.md) | Interface for a visitor that is accepted by all types (classic visitor-pattern). |
7171

7272
## Variables
7373

src/types/interface.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import { unknownRecord } from './unknown';
1010

1111
testTypeImpl({
1212
name: '{ force?: boolean }',
13-
type: partial({ force: boolean }),
13+
type: [
14+
partial({ force: boolean }),
15+
// very contrived way to get the same result, should behave exactly the same
16+
object('CustomNameThatIsRemoved', { force: boolean }).withOptional({ name: null }, { force: boolean }),
17+
],
1418
basicType: 'object',
1519
validValues: [{ force: true }, { force: true, otherOpts: 'also valid', [stripped]: { force: true } }, {}],
1620
invalidValues: [
@@ -25,7 +29,10 @@ testTypeImpl({
2529

2630
testTypeImpl({
2731
name: '{ really?: boolean.autoCast, amounts?: { begin: number.autoCast, end: number.autoCast } }',
28-
type: partial({ really: boolean, amounts: object({ begin: number, end: number }) }).autoCastAll,
32+
type: [
33+
partial({ really: boolean, amounts: object({ begin: number, end: number }) }).autoCastAll,
34+
partial({ really: boolean.autoCast }).withOptional({ amounts: object({ begin: number.autoCast, end: number.autoCast }) }),
35+
],
2936
basicType: 'object',
3037
validValues: [{}, { really: true }, { really: false, amounts: { begin: 123, end: -456 } }, { amounts: { begin: 123, end: -456 } }],
3138
validConversions: [

src/types/interface.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,21 @@ export interface InterfaceTypeOptionsWithPartial extends InterfaceTypeOptions {
5757
partial?: boolean;
5858
}
5959

60+
/**
61+
* Options for {@link InterfaceType.withOptional}, {@link InterfaceType.withRequired} and {@link InterfaceType.mergeWith}.
62+
*/
6063
export interface InterfaceMergeOptions {
61-
/** The optional name for the type, uses a default TypeScript-like name if no name is given. */
62-
name?: string;
64+
/**
65+
* The optional name for the new type, or `null` to force a generated TypeScript-like name.
66+
*
67+
* @remarks
68+
* When omitted, it will follow the name of original type (on the left). It will either use the custom name of that type or generate a
69+
* new default TypeScript-like name if the type did not have a custom name.
70+
*
71+
* Use this `name` setting with a `string` to provide a new custom name or use `null` to force a generated TypeScript-like name, even if the
72+
* original type has a custom name.
73+
*/
74+
name?: string | null;
6375

6476
/**
6577
* When set, do not apply the custom validations from the base types onto the new merged type.
@@ -227,12 +239,18 @@ export class InterfaceType<Props extends Properties, ResultType>
227239
}
228240

229241
private _mergeWith<OtherProps extends Properties, OtherType>(
230-
{ name = this.isDefaultName ? undefined : this.name, omitParsers, omitValidations }: Partial<InterfaceMergeOptions>,
242+
{ name: nameOption, omitParsers, omitValidations }: Partial<InterfaceMergeOptions>,
231243
otherPropsInfo: PropertiesInfo<OtherProps>,
232244
otherCustomValidators: ReadonlyArray<Validator<unknown>>,
233245
otherHasCustomParser: boolean,
234246
method: string,
235247
): MergeType<Props, ResultType, OtherProps, OtherType> {
248+
const name =
249+
nameOption === null
250+
? // if the option was set to `null`, then force a new default name
251+
undefined
252+
: // otherwise default to what the current type has
253+
nameOption ?? (this.isDefaultName ? undefined : this.name);
236254
const customValidators = omitValidations ? [] : [...this.customValidators, ...otherCustomValidators];
237255
if (customValidators.length) {
238256
// Check that we have no conflicting properties. If there are no conflicting properties then each validator is still safe to

src/utils/collection-utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function decodeOptionalName<Rest extends unknown[]>(args: [string, ...Res
88
return (typeof args[0] === 'string' ? args : [undefined, ...args]) as [string | undefined, ...Rest];
99
}
1010

11-
export function decodeOptionalOptions<Options extends { name?: string }, OtherParam>(
11+
export function decodeOptionalOptions<Options extends { name?: string | null }, OtherParam>(
1212
args: [other: OtherParam] | [name: string, other: OtherParam] | [options: Options, other: OtherParam],
1313
): [Partial<Options>, OtherParam] {
1414
if (args.length === 1) return [{}, args[0]];

0 commit comments

Comments
 (0)