mirror of
https://github.com/sindresorhus/type-fest.git
synced 2026-01-25 14:57:30 +00:00
Refactor how options are handled for types (#1081)
This commit is contained in:
parent
ed8c987129
commit
db76e5b15f
14
source/camel-case.d.ts
vendored
14
source/camel-case.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {Words} from './words';
|
||||
|
||||
/**
|
||||
@ -14,12 +15,16 @@ export type CamelCaseOptions = {
|
||||
preserveConsecutiveUppercase?: boolean;
|
||||
};
|
||||
|
||||
export type DefaultCamelCaseOptions = {
|
||||
preserveConsecutiveUppercase: true;
|
||||
};
|
||||
|
||||
/**
|
||||
Convert an array of words to camel-case.
|
||||
*/
|
||||
type CamelCaseFromArray<
|
||||
Words extends string[],
|
||||
Options extends CamelCaseOptions,
|
||||
Options extends Required<CamelCaseOptions>,
|
||||
OutputString extends string = '',
|
||||
> = Words extends [
|
||||
infer FirstWord extends string,
|
||||
@ -73,8 +78,11 @@ const dbResult: CamelCasedProperties<RawOptions> = {
|
||||
@category Change case
|
||||
@category Template literal
|
||||
*/
|
||||
export type CamelCase<Type, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = Type extends string
|
||||
export type CamelCase<Type, Options extends CamelCaseOptions = {}> = Type extends string
|
||||
? string extends Type
|
||||
? Type
|
||||
: Uncapitalize<CamelCaseFromArray<Words<Type extends Uppercase<Type> ? Lowercase<Type> : Type>, Options>>
|
||||
: Uncapitalize<CamelCaseFromArray<
|
||||
Words<Type extends Uppercase<Type> ? Lowercase<Type> : Type>,
|
||||
ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>
|
||||
>>
|
||||
: Type;
|
||||
|
||||
15
source/camel-cased-properties-deep.d.ts
vendored
15
source/camel-cased-properties-deep.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import type {CamelCase, CamelCaseOptions} from './camel-case';
|
||||
import type {NonRecursiveType} from './internal';
|
||||
import type {CamelCase, CamelCaseOptions, DefaultCamelCaseOptions} from './camel-case';
|
||||
import type {ApplyDefaultOptions, NonRecursiveType} from './internal';
|
||||
import type {UnknownArray} from './unknown-array';
|
||||
|
||||
/**
|
||||
@ -48,15 +48,20 @@ const result: CamelCasedPropertiesDeep<UserWithFriends> = {
|
||||
*/
|
||||
export type CamelCasedPropertiesDeep<
|
||||
Value,
|
||||
Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true},
|
||||
Options extends CamelCaseOptions = {},
|
||||
> = _CamelCasedPropertiesDeep<Value, ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>>;
|
||||
|
||||
type _CamelCasedPropertiesDeep<
|
||||
Value,
|
||||
Options extends Required<CamelCaseOptions>,
|
||||
> = Value extends NonRecursiveType
|
||||
? Value
|
||||
: Value extends UnknownArray
|
||||
? CamelCasedPropertiesArrayDeep<Value>
|
||||
: Value extends Set<infer U>
|
||||
? Set<CamelCasedPropertiesDeep<U, Options>>
|
||||
? Set<_CamelCasedPropertiesDeep<U, Options>>
|
||||
: {
|
||||
[K in keyof Value as CamelCase<K, Options>]: CamelCasedPropertiesDeep<
|
||||
[K in keyof Value as CamelCase<K, Options>]: _CamelCasedPropertiesDeep<
|
||||
Value[K],
|
||||
Options
|
||||
>;
|
||||
|
||||
9
source/camel-cased-properties.d.ts
vendored
9
source/camel-cased-properties.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type {CamelCase, CamelCaseOptions} from './camel-case';
|
||||
import type {CamelCase, CamelCaseOptions, DefaultCamelCaseOptions} from './camel-case';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
|
||||
/**
|
||||
Convert object properties to camel case but not recursively.
|
||||
@ -27,10 +28,12 @@ const result: CamelCasedProperties<User> = {
|
||||
@category Template literal
|
||||
@category Object
|
||||
*/
|
||||
export type CamelCasedProperties<Value, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = Value extends Function
|
||||
export type CamelCasedProperties<Value, Options extends CamelCaseOptions = {}> = Value extends Function
|
||||
? Value
|
||||
: Value extends Array<infer U>
|
||||
? Value
|
||||
: {
|
||||
[K in keyof Value as CamelCase<K, Options>]: Value[K];
|
||||
[K in keyof Value as
|
||||
CamelCase<K, ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>>
|
||||
]: Value[K];
|
||||
};
|
||||
|
||||
18
source/conditional-pick-deep.d.ts
vendored
18
source/conditional-pick-deep.d.ts
vendored
@ -3,7 +3,7 @@ import type {ConditionalExcept} from './conditional-except';
|
||||
import type {ConditionalSimplifyDeep} from './conditional-simplify';
|
||||
import type {UnknownRecord} from './unknown-record';
|
||||
import type {EmptyObject} from './empty-object';
|
||||
import type {IsPlainObject} from './internal';
|
||||
import type {ApplyDefaultOptions, IsPlainObject} from './internal';
|
||||
|
||||
/**
|
||||
Used to mark properties that should be excluded.
|
||||
@ -33,6 +33,10 @@ export type ConditionalPickDeepOptions = {
|
||||
condition?: 'extends' | 'equality';
|
||||
};
|
||||
|
||||
type DefaultConditionalPickDeepOptions = {
|
||||
condition: 'extends';
|
||||
};
|
||||
|
||||
/**
|
||||
Pick keys recursively from the shape that matches the given condition.
|
||||
|
||||
@ -95,10 +99,20 @@ export type ConditionalPickDeep<
|
||||
Type,
|
||||
Condition,
|
||||
Options extends ConditionalPickDeepOptions = {},
|
||||
> = _ConditionalPickDeep<
|
||||
Type,
|
||||
Condition,
|
||||
ApplyDefaultOptions<ConditionalPickDeepOptions, DefaultConditionalPickDeepOptions, Options>
|
||||
>;
|
||||
|
||||
type _ConditionalPickDeep<
|
||||
Type,
|
||||
Condition,
|
||||
Options extends Required<ConditionalPickDeepOptions>,
|
||||
> = ConditionalSimplifyDeep<ConditionalExcept<{
|
||||
[Key in keyof Type]: AssertCondition<Type[Key], Condition, Options> extends true
|
||||
? Type[Key]
|
||||
: IsPlainObject<Type[Key]> extends true
|
||||
? ConditionalPickDeep<Type[Key], Condition, Options>
|
||||
? _ConditionalPickDeep<Type[Key], Condition, Options>
|
||||
: typeof conditionalPickDeepSymbol;
|
||||
}, (typeof conditionalPickDeepSymbol | undefined) | EmptyObject>, never, UnknownRecord>;
|
||||
|
||||
17
source/delimiter-case.d.ts
vendored
17
source/delimiter-case.d.ts
vendored
@ -1,5 +1,9 @@
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {IsStringLiteral} from './is-literal';
|
||||
import type {Words, WordsOptions} from './words';
|
||||
import type {Merge} from './merge';
|
||||
import type {DefaultWordsOptions, Words, WordsOptions} from './words';
|
||||
|
||||
export type DefaultDelimiterCaseOptions = Merge<DefaultWordsOptions, {splitOnNumbers: false}>;
|
||||
|
||||
/**
|
||||
Convert an array of words to delimiter case starting with a delimiter with input capitalization.
|
||||
@ -61,13 +65,12 @@ const rawCliOptions: OddlyCasedProperties<SomeOptions> = {
|
||||
export type DelimiterCase<
|
||||
Value,
|
||||
Delimiter extends string,
|
||||
Options extends WordsOptions = {splitOnNumbers: false},
|
||||
Options extends WordsOptions = {},
|
||||
> = Value extends string
|
||||
? IsStringLiteral<Value> extends false
|
||||
? Value
|
||||
: Lowercase<
|
||||
RemoveFirstLetter<
|
||||
DelimiterCaseFromArray<Words<Value, Options>, Delimiter>
|
||||
>
|
||||
>
|
||||
: Lowercase<RemoveFirstLetter<DelimiterCaseFromArray<
|
||||
Words<Value, ApplyDefaultOptions<WordsOptions, DefaultDelimiterCaseOptions, Options>>,
|
||||
Delimiter
|
||||
>>>
|
||||
: Value;
|
||||
|
||||
10
source/except.d.ts
vendored
10
source/except.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {IsEqual} from './is-equal';
|
||||
|
||||
/**
|
||||
@ -40,6 +41,10 @@ type ExceptOptions = {
|
||||
requireExactProps?: boolean;
|
||||
};
|
||||
|
||||
type DefaultExceptOptions = {
|
||||
requireExactProps: false;
|
||||
};
|
||||
|
||||
/**
|
||||
Create a type from an object type without certain keys.
|
||||
|
||||
@ -93,7 +98,10 @@ type PostPayload = Except<UserData, 'email'>;
|
||||
|
||||
@category Object
|
||||
*/
|
||||
export type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {requireExactProps: false}> = {
|
||||
export type Except<ObjectType, KeysType extends keyof ObjectType, Options extends ExceptOptions = {}> =
|
||||
_Except<ObjectType, KeysType, ApplyDefaultOptions<ExceptOptions, DefaultExceptOptions, Options>>;
|
||||
|
||||
type _Except<ObjectType, KeysType extends keyof ObjectType, Options extends Required<ExceptOptions>> = {
|
||||
[KeyType in keyof ObjectType as Filter<KeyType, KeysType>]: ObjectType[KeyType];
|
||||
} & (Options['requireExactProps'] extends true
|
||||
? Partial<Record<KeysType, never>>
|
||||
|
||||
23
source/get.d.ts
vendored
23
source/get.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import type {StringDigit, ToString} from './internal';
|
||||
import type {ApplyDefaultOptions, StringDigit, ToString} from './internal';
|
||||
import type {LiteralStringUnion} from './literal-union';
|
||||
import type {Paths} from './paths';
|
||||
import type {Split} from './split';
|
||||
@ -15,10 +15,14 @@ type GetOptions = {
|
||||
strict?: boolean;
|
||||
};
|
||||
|
||||
type DefaultGetOptions = {
|
||||
strict: true;
|
||||
};
|
||||
|
||||
/**
|
||||
Like the `Get` type but receives an array of strings as a path parameter.
|
||||
*/
|
||||
type GetWithPath<BaseType, Keys, Options extends GetOptions = {}> =
|
||||
type GetWithPath<BaseType, Keys, Options extends Required<GetOptions>> =
|
||||
Keys extends readonly []
|
||||
? BaseType
|
||||
: Keys extends readonly [infer Head, ...infer Tail]
|
||||
@ -32,7 +36,7 @@ type GetWithPath<BaseType, Keys, Options extends GetOptions = {}> =
|
||||
/**
|
||||
Adds `undefined` to `Type` if `strict` is enabled.
|
||||
*/
|
||||
type Strictify<Type, Options extends GetOptions> =
|
||||
type Strictify<Type, Options extends Required<GetOptions>> =
|
||||
Options['strict'] extends false ? Type : (Type | undefined);
|
||||
|
||||
/**
|
||||
@ -41,7 +45,7 @@ If `Options['strict']` is `true`, includes `undefined` in the returned type when
|
||||
Known limitations:
|
||||
- Does not include `undefined` in the type on object types with an index signature (for example, `{a: string; [key: string]: string}`).
|
||||
*/
|
||||
type StrictPropertyOf<BaseType, Key extends keyof BaseType, Options extends GetOptions> =
|
||||
type StrictPropertyOf<BaseType, Key extends keyof BaseType, Options extends Required<GetOptions>> =
|
||||
Record<string, any> extends BaseType
|
||||
? string extends keyof BaseType
|
||||
? Strictify<BaseType[Key], Options> // Record<string, any>
|
||||
@ -122,7 +126,7 @@ Note:
|
||||
- Returns `unknown` if `Key` is not a property of `BaseType`, since TypeScript uses structural typing, and it cannot be guaranteed that extra properties unknown to the type system will exist at runtime.
|
||||
- Returns `undefined` from nullish values, to match the behaviour of most deep-key libraries like `lodash`, `dot-prop`, etc.
|
||||
*/
|
||||
type PropertyOf<BaseType, Key extends string, Options extends GetOptions = {}> =
|
||||
type PropertyOf<BaseType, Key extends string, Options extends Required<GetOptions>> =
|
||||
BaseType extends null | undefined
|
||||
? undefined
|
||||
: Key extends keyof BaseType
|
||||
@ -206,5 +210,10 @@ export type Get<
|
||||
Path extends
|
||||
| readonly string[]
|
||||
| LiteralStringUnion<ToString<Paths<BaseType, {bracketNotation: false; maxRecursionDepth: 2}> | Paths<BaseType, {bracketNotation: true; maxRecursionDepth: 2}>>>,
|
||||
Options extends GetOptions = {}> =
|
||||
GetWithPath<BaseType, Path extends string ? ToPath<Path> : Path, Options>;
|
||||
Options extends GetOptions = {},
|
||||
> =
|
||||
GetWithPath<
|
||||
BaseType,
|
||||
Path extends string ? ToPath<Path> : Path,
|
||||
ApplyDefaultOptions<GetOptions, DefaultGetOptions, Options>
|
||||
>;
|
||||
|
||||
71
source/internal/object.d.ts
vendored
71
source/internal/object.d.ts
vendored
@ -2,6 +2,11 @@ import type {Simplify} from '../simplify';
|
||||
import type {UnknownArray} from '../unknown-array';
|
||||
import type {IsEqual} from '../is-equal';
|
||||
import type {KeysOfUnion} from '../keys-of-union';
|
||||
import type {RequiredKeysOf} from '../required-keys-of';
|
||||
import type {Merge} from '../merge';
|
||||
import type {IfAny} from '../if-any';
|
||||
import type {IfNever} from '../if-never';
|
||||
import type {OptionalKeysOf} from '../optional-keys-of';
|
||||
import type {FilterDefinedKeys, FilterOptionalKeys} from './keys';
|
||||
import type {NonRecursiveType} from './type';
|
||||
import type {ToString} from './string';
|
||||
@ -159,3 +164,69 @@ type ReadonlyKeys = ReadonlyKeysOfUnion<User | Post>;
|
||||
export type ReadonlyKeysOfUnion<Union> = Union extends unknown ? keyof {
|
||||
[Key in keyof Union as IsEqual<{[K in Key]: Union[Key]}, {readonly [K in Key]: Union[Key]}> extends true ? Key : never]: never
|
||||
} : never;
|
||||
|
||||
/**
|
||||
Merges user specified options with default options.
|
||||
|
||||
@example
|
||||
```
|
||||
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
||||
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
|
||||
type SpecifiedOptions = {leavesOnly: true};
|
||||
|
||||
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
||||
//=> {maxRecursionDepth: 10; leavesOnly: true}
|
||||
```
|
||||
|
||||
@example
|
||||
```
|
||||
// Complains if default values are not provided for optional options
|
||||
|
||||
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
||||
type DefaultPathsOptions = {maxRecursionDepth: 10};
|
||||
type SpecifiedOptions = {};
|
||||
|
||||
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
// Property 'leavesOnly' is missing in type 'DefaultPathsOptions' but required in type '{ maxRecursionDepth: number; leavesOnly: boolean; }'.
|
||||
```
|
||||
|
||||
@example
|
||||
```
|
||||
// Complains if an option's default type does not conform to the expected type
|
||||
|
||||
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
||||
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: 'no'};
|
||||
type SpecifiedOptions = {};
|
||||
|
||||
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
|
||||
```
|
||||
|
||||
@example
|
||||
```
|
||||
// Complains if an option's specified type does not conform to the expected type
|
||||
|
||||
type PathsOptions = {maxRecursionDepth?: number; leavesOnly?: boolean};
|
||||
type DefaultPathsOptions = {maxRecursionDepth: 10; leavesOnly: false};
|
||||
type SpecifiedOptions = {leavesOnly: 'yes'};
|
||||
|
||||
type Result = ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, SpecifiedOptions>;
|
||||
// ~~~~~~~~~~~~~~~~
|
||||
// Types of property 'leavesOnly' are incompatible. Type 'string' is not assignable to type 'boolean'.
|
||||
```
|
||||
*/
|
||||
export type ApplyDefaultOptions<
|
||||
Options extends object,
|
||||
Defaults extends Simplify<Omit<Required<Options>, RequiredKeysOf<Options>> & Partial<Record<RequiredKeysOf<Options>, never>>>,
|
||||
SpecifiedOptions extends Options,
|
||||
> =
|
||||
IfAny<SpecifiedOptions, Defaults,
|
||||
IfNever<SpecifiedOptions, Defaults,
|
||||
Simplify<Merge<Defaults, {
|
||||
[Key in keyof SpecifiedOptions
|
||||
as Key extends OptionalKeysOf<Options> ? undefined extends SpecifiedOptions[Key] ? never : Key : Key
|
||||
]: SpecifiedOptions[Key]
|
||||
}> & Required<Options>> // `& Required<Options>` ensures that `ApplyDefaultOptions<SomeOption, ...>` is always assignable to `Required<SomeOption>`
|
||||
>>;
|
||||
|
||||
13
source/is-tuple.d.ts
vendored
13
source/is-tuple.d.ts
vendored
@ -1,5 +1,6 @@
|
||||
import type {IfAny} from './if-any';
|
||||
import type {IfNever} from './if-never';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {UnknownArray} from './unknown-array';
|
||||
|
||||
/**
|
||||
@ -28,6 +29,10 @@ export type IsTupleOptions = {
|
||||
fixedLengthOnly?: boolean;
|
||||
};
|
||||
|
||||
type DefaultIsTupleOptions = {
|
||||
fixedLengthOnly: true;
|
||||
};
|
||||
|
||||
/**
|
||||
Returns a boolean for whether the given array is a tuple.
|
||||
|
||||
@ -63,7 +68,13 @@ type RestItemsAllowed = IsTuple<[1, 2, ...number[]], {fixedLengthOnly: false}>;
|
||||
*/
|
||||
export type IsTuple<
|
||||
TArray extends UnknownArray,
|
||||
Options extends IsTupleOptions = {fixedLengthOnly: true},
|
||||
Options extends IsTupleOptions = {},
|
||||
> =
|
||||
_IsTuple<TArray, ApplyDefaultOptions<IsTupleOptions, DefaultIsTupleOptions, Options>>;
|
||||
|
||||
type _IsTuple<
|
||||
TArray extends UnknownArray,
|
||||
Options extends Required<IsTupleOptions>,
|
||||
> =
|
||||
IfAny<TArray, boolean, IfNever<TArray, false,
|
||||
TArray extends unknown // For distributing `TArray`
|
||||
|
||||
7
source/kebab-case.d.ts
vendored
7
source/kebab-case.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type {DelimiterCase} from './delimiter-case';
|
||||
import type {DefaultDelimiterCaseOptions, DelimiterCase} from './delimiter-case';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {WordsOptions} from './words';
|
||||
|
||||
/**
|
||||
@ -39,5 +40,5 @@ const rawCliOptions: KebabCasedProperties<CliOptions> = {
|
||||
*/
|
||||
export type KebabCase<
|
||||
Value,
|
||||
Options extends WordsOptions = {splitOnNumbers: false},
|
||||
> = DelimiterCase<Value, '-', Options>;
|
||||
Options extends WordsOptions = {},
|
||||
> = DelimiterCase<Value, '-', ApplyDefaultOptions<WordsOptions, DefaultDelimiterCaseOptions, Options>>;
|
||||
|
||||
28
source/partial-deep.d.ts
vendored
28
source/partial-deep.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import type {BuiltIns} from './internal';
|
||||
import type {ApplyDefaultOptions, BuiltIns} from './internal';
|
||||
|
||||
/**
|
||||
@see {@link PartialDeep}
|
||||
@ -38,6 +38,11 @@ export type PartialDeepOptions = {
|
||||
readonly allowUndefinedInNonTupleArrays?: boolean;
|
||||
};
|
||||
|
||||
type DefaultPartialDeepOptions = {
|
||||
recurseIntoArrays: false;
|
||||
allowUndefinedInNonTupleArrays: true;
|
||||
};
|
||||
|
||||
/**
|
||||
Create a type from another type with all keys and nested keys set to optional.
|
||||
|
||||
@ -87,7 +92,10 @@ const partialSettings: PartialDeep<Settings, {recurseIntoArrays: true}> = {
|
||||
@category Set
|
||||
@category Map
|
||||
*/
|
||||
export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends BuiltIns | (((...arguments_: any[]) => unknown)) | (new (...arguments_: any[]) => unknown)
|
||||
export type PartialDeep<T, Options extends PartialDeepOptions = {}> =
|
||||
_PartialDeep<T, ApplyDefaultOptions<PartialDeepOptions, DefaultPartialDeepOptions, Options>>;
|
||||
|
||||
type _PartialDeep<T, Options extends Required<PartialDeepOptions>> = T extends BuiltIns | (((...arguments_: any[]) => unknown)) | (new (...arguments_: any[]) => unknown)
|
||||
? T
|
||||
: T extends Map<infer KeyType, infer ValueType>
|
||||
? PartialMapDeep<KeyType, ValueType, Options>
|
||||
@ -102,8 +110,8 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends
|
||||
? Options['recurseIntoArrays'] extends true
|
||||
? ItemType[] extends T // Test for arrays (non-tuples) specifically
|
||||
? readonly ItemType[] extends T // Differentiate readonly and mutable arrays
|
||||
? ReadonlyArray<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
|
||||
: Array<PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
|
||||
? ReadonlyArray<_PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
|
||||
: Array<_PartialDeep<Options['allowUndefinedInNonTupleArrays'] extends false ? ItemType : ItemType | undefined, Options>>
|
||||
: PartialObjectDeep<T, Options> // Tuples behave properly
|
||||
: T // If they don't opt into array testing, just use the original type
|
||||
: PartialObjectDeep<T, Options>
|
||||
@ -112,26 +120,26 @@ export type PartialDeep<T, Options extends PartialDeepOptions = {}> = T extends
|
||||
/**
|
||||
Same as `PartialDeep`, but accepts only `Map`s and as inputs. Internal helper for `PartialDeep`.
|
||||
*/
|
||||
type PartialMapDeep<KeyType, ValueType, Options extends PartialDeepOptions> = {} & Map<PartialDeep<KeyType, Options>, PartialDeep<ValueType, Options>>;
|
||||
type PartialMapDeep<KeyType, ValueType, Options extends Required<PartialDeepOptions>> = {} & Map<_PartialDeep<KeyType, Options>, _PartialDeep<ValueType, Options>>;
|
||||
|
||||
/**
|
||||
Same as `PartialDeep`, but accepts only `Set`s as inputs. Internal helper for `PartialDeep`.
|
||||
*/
|
||||
type PartialSetDeep<T, Options extends PartialDeepOptions> = {} & Set<PartialDeep<T, Options>>;
|
||||
type PartialSetDeep<T, Options extends Required<PartialDeepOptions>> = {} & Set<_PartialDeep<T, Options>>;
|
||||
|
||||
/**
|
||||
Same as `PartialDeep`, but accepts only `ReadonlyMap`s as inputs. Internal helper for `PartialDeep`.
|
||||
*/
|
||||
type PartialReadonlyMapDeep<KeyType, ValueType, Options extends PartialDeepOptions> = {} & ReadonlyMap<PartialDeep<KeyType, Options>, PartialDeep<ValueType, Options>>;
|
||||
type PartialReadonlyMapDeep<KeyType, ValueType, Options extends Required<PartialDeepOptions>> = {} & ReadonlyMap<_PartialDeep<KeyType, Options>, _PartialDeep<ValueType, Options>>;
|
||||
|
||||
/**
|
||||
Same as `PartialDeep`, but accepts only `ReadonlySet`s as inputs. Internal helper for `PartialDeep`.
|
||||
*/
|
||||
type PartialReadonlySetDeep<T, Options extends PartialDeepOptions> = {} & ReadonlySet<PartialDeep<T, Options>>;
|
||||
type PartialReadonlySetDeep<T, Options extends Required<PartialDeepOptions>> = {} & ReadonlySet<_PartialDeep<T, Options>>;
|
||||
|
||||
/**
|
||||
Same as `PartialDeep`, but accepts only `object`s as inputs. Internal helper for `PartialDeep`.
|
||||
*/
|
||||
type PartialObjectDeep<ObjectType extends object, Options extends PartialDeepOptions> = {
|
||||
[KeyType in keyof ObjectType]?: PartialDeep<ObjectType[KeyType], Options>
|
||||
type PartialObjectDeep<ObjectType extends object, Options extends Required<PartialDeepOptions>> = {
|
||||
[KeyType in keyof ObjectType]?: _PartialDeep<ObjectType[KeyType], Options>
|
||||
};
|
||||
|
||||
21
source/partial-on-undefined-deep.d.ts
vendored
21
source/partial-on-undefined-deep.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import type {IfUnknown} from './if-unknown';
|
||||
import type {BuiltIns, LiteralKeyOf} from './internal';
|
||||
import type {ApplyDefaultOptions, BuiltIns, LiteralKeyOf} from './internal';
|
||||
import type {Merge} from './merge';
|
||||
|
||||
/**
|
||||
@ -14,6 +14,10 @@ export type PartialOnUndefinedDeepOptions = {
|
||||
readonly recurseIntoArrays?: boolean;
|
||||
};
|
||||
|
||||
type DefaultPartialOnUndefinedDeepOptions = {
|
||||
recurseIntoArrays: false;
|
||||
};
|
||||
|
||||
/**
|
||||
Create a deep version of another type where all keys accepting `undefined` type are set to optional.
|
||||
|
||||
@ -47,7 +51,10 @@ const testSettings: PartialOnUndefinedDeep<Settings> = {
|
||||
|
||||
@category Object
|
||||
*/
|
||||
export type PartialOnUndefinedDeep<T, Options extends PartialOnUndefinedDeepOptions = {}> = T extends Record<any, any> | undefined
|
||||
export type PartialOnUndefinedDeep<T, Options extends PartialOnUndefinedDeepOptions = {}> =
|
||||
_PartialOnUndefinedDeep<T, ApplyDefaultOptions<PartialOnUndefinedDeepOptions, DefaultPartialOnUndefinedDeepOptions, Options>>;
|
||||
|
||||
type _PartialOnUndefinedDeep<T, Options extends Required<PartialOnUndefinedDeepOptions>> = T extends Record<any, any> | undefined
|
||||
? {[KeyType in keyof T as undefined extends T[KeyType] ? IfUnknown<T[KeyType], never, KeyType> : never]?: PartialOnUndefinedDeepValue<T[KeyType], Options>} extends infer U // Make a partial type with all value types accepting undefined (and set them optional)
|
||||
? Merge<{[KeyType in keyof T as KeyType extends LiteralKeyOf<U> ? never : KeyType]: PartialOnUndefinedDeepValue<T[KeyType], Options>}, U> // Join all remaining keys not treated in U
|
||||
: never // Should not happen
|
||||
@ -56,16 +63,16 @@ export type PartialOnUndefinedDeep<T, Options extends PartialOnUndefinedDeepOpti
|
||||
/**
|
||||
Utility type to get the value type by key and recursively call `PartialOnUndefinedDeep` to transform sub-objects.
|
||||
*/
|
||||
type PartialOnUndefinedDeepValue<T, Options extends PartialOnUndefinedDeepOptions> = T extends BuiltIns | ((...arguments_: any[]) => unknown)
|
||||
type PartialOnUndefinedDeepValue<T, Options extends Required<PartialOnUndefinedDeepOptions>> = T extends BuiltIns | ((...arguments_: any[]) => unknown)
|
||||
? T
|
||||
: T extends ReadonlyArray<infer U> // Test if type is array or tuple
|
||||
? Options['recurseIntoArrays'] extends true // Check if option is activated
|
||||
? U[] extends T // Check if array not tuple
|
||||
? readonly U[] extends T
|
||||
? ReadonlyArray<PartialOnUndefinedDeep<U, Options>> // Readonly array treatment
|
||||
: Array<PartialOnUndefinedDeep<U, Options>> // Mutable array treatment
|
||||
: PartialOnUndefinedDeep<{[Key in keyof T]: PartialOnUndefinedDeep<T[Key], Options>}, Options> // Tuple treatment
|
||||
? ReadonlyArray<_PartialOnUndefinedDeep<U, Options>> // Readonly array treatment
|
||||
: Array<_PartialOnUndefinedDeep<U, Options>> // Mutable array treatment
|
||||
: _PartialOnUndefinedDeep<{[Key in keyof T]: _PartialOnUndefinedDeep<T[Key], Options>}, Options> // Tuple treatment
|
||||
: T
|
||||
: T extends Record<any, any> | undefined
|
||||
? PartialOnUndefinedDeep<T, Options>
|
||||
? _PartialOnUndefinedDeep<T, Options>
|
||||
: unknown;
|
||||
|
||||
8
source/pascal-case.d.ts
vendored
8
source/pascal-case.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type {CamelCase, CamelCaseOptions} from './camel-case';
|
||||
import type {CamelCase, CamelCaseOptions, DefaultCamelCaseOptions} from './camel-case';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
|
||||
/**
|
||||
Converts a string literal to pascal-case.
|
||||
@ -33,6 +34,9 @@ const dbResult: CamelCasedProperties<ModelProps> = {
|
||||
@category Change case
|
||||
@category Template literal
|
||||
*/
|
||||
export type PascalCase<Value, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = CamelCase<Value, Options> extends string
|
||||
export type PascalCase<Value, Options extends CamelCaseOptions = {}> =
|
||||
_PascalCase<Value, ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>>;
|
||||
|
||||
type _PascalCase<Value, Options extends Required<CamelCaseOptions>> = CamelCase<Value, Options> extends string
|
||||
? Capitalize<CamelCase<Value, Options>>
|
||||
: CamelCase<Value, Options>;
|
||||
|
||||
14
source/pascal-cased-properties-deep.d.ts
vendored
14
source/pascal-cased-properties-deep.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type {CamelCaseOptions} from './camel-case';
|
||||
import type {CamelCaseOptions, DefaultCamelCaseOptions} from './camel-case';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {PascalCase} from './pascal-case';
|
||||
|
||||
/**
|
||||
@ -45,11 +46,14 @@ const result: PascalCasedPropertiesDeep<UserWithFriends> = {
|
||||
@category Template literal
|
||||
@category Object
|
||||
*/
|
||||
export type PascalCasedPropertiesDeep<Value, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = Value extends Function | Date | RegExp
|
||||
export type PascalCasedPropertiesDeep<Value, Options extends CamelCaseOptions = {}> =
|
||||
_PascalCasedPropertiesDeep<Value, ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>>;
|
||||
|
||||
type _PascalCasedPropertiesDeep<Value, Options extends Required<CamelCaseOptions>> = Value extends Function | Date | RegExp
|
||||
? Value
|
||||
: Value extends Array<infer U>
|
||||
? Array<PascalCasedPropertiesDeep<U, Options>>
|
||||
? Array<_PascalCasedPropertiesDeep<U, Options>>
|
||||
: Value extends Set<infer U>
|
||||
? Set<PascalCasedPropertiesDeep<U, Options>> : {
|
||||
[K in keyof Value as PascalCase<K, Options>]: PascalCasedPropertiesDeep<Value[K], Options>;
|
||||
? Set<_PascalCasedPropertiesDeep<U, Options>> : {
|
||||
[K in keyof Value as PascalCase<K, Options>]: _PascalCasedPropertiesDeep<Value[K], Options>;
|
||||
};
|
||||
|
||||
7
source/pascal-cased-properties.d.ts
vendored
7
source/pascal-cased-properties.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type {CamelCaseOptions} from './camel-case';
|
||||
import type {CamelCaseOptions, DefaultCamelCaseOptions} from './camel-case';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {PascalCase} from './pascal-case';
|
||||
|
||||
/**
|
||||
@ -28,8 +29,8 @@ const result: PascalCasedProperties<User> = {
|
||||
@category Template literal
|
||||
@category Object
|
||||
*/
|
||||
export type PascalCasedProperties<Value, Options extends CamelCaseOptions = {preserveConsecutiveUppercase: true}> = Value extends Function
|
||||
export type PascalCasedProperties<Value, Options extends CamelCaseOptions = {}> = Value extends Function
|
||||
? Value
|
||||
: Value extends Array<infer U>
|
||||
? Value
|
||||
: {[K in keyof Value as PascalCase<K, Options>]: Value[K]};
|
||||
: {[K in keyof Value as PascalCase<K, ApplyDefaultOptions<CamelCaseOptions, DefaultCamelCaseOptions, Options>>]: Value[K]};
|
||||
|
||||
13
source/paths.d.ts
vendored
13
source/paths.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import type {StaticPartOfArray, VariablePartOfArray, NonRecursiveType, ToString, IsNumberLike} from './internal';
|
||||
import type {StaticPartOfArray, VariablePartOfArray, NonRecursiveType, ToString, IsNumberLike, ApplyDefaultOptions} from './internal';
|
||||
import type {EmptyObject} from './empty-object';
|
||||
import type {IsAny} from './is-any';
|
||||
import type {UnknownArray} from './unknown-array';
|
||||
@ -176,16 +176,7 @@ open('listB.1'); // TypeError. Because listB only has one element.
|
||||
@category Object
|
||||
@category Array
|
||||
*/
|
||||
export type Paths<T, Options extends PathsOptions = {}> = _Paths<T, {
|
||||
// Set default maxRecursionDepth to 10
|
||||
maxRecursionDepth: Options['maxRecursionDepth'] extends number ? Options['maxRecursionDepth'] : DefaultPathsOptions['maxRecursionDepth'];
|
||||
// Set default bracketNotation to false
|
||||
bracketNotation: Options['bracketNotation'] extends boolean ? Options['bracketNotation'] : DefaultPathsOptions['bracketNotation'];
|
||||
// Set default leavesOnly to false
|
||||
leavesOnly: Options['leavesOnly'] extends boolean ? Options['leavesOnly'] : DefaultPathsOptions['leavesOnly'];
|
||||
// Set default depth to number
|
||||
depth: Options['depth'] extends number ? Options['depth'] : DefaultPathsOptions['depth'];
|
||||
}>;
|
||||
export type Paths<T, Options extends PathsOptions = {}> = _Paths<T, ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, Options>>;
|
||||
|
||||
type _Paths<T, Options extends Required<PathsOptions>> =
|
||||
T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
|
||||
|
||||
10
source/replace.d.ts
vendored
10
source/replace.d.ts
vendored
@ -1,7 +1,13 @@
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
|
||||
type ReplaceOptions = {
|
||||
all?: boolean;
|
||||
};
|
||||
|
||||
type DefaultReplaceOptions = {
|
||||
all: false;
|
||||
};
|
||||
|
||||
/**
|
||||
Represents a string with some or all matches replaced by a replacement.
|
||||
|
||||
@ -60,13 +66,13 @@ export type Replace<
|
||||
Search extends string,
|
||||
Replacement extends string,
|
||||
Options extends ReplaceOptions = {},
|
||||
> = _Replace<Input, Search, Replacement, Options>;
|
||||
> = _Replace<Input, Search, Replacement, ApplyDefaultOptions<ReplaceOptions, DefaultReplaceOptions, Options>>;
|
||||
|
||||
type _Replace<
|
||||
Input extends string,
|
||||
Search extends string,
|
||||
Replacement extends string,
|
||||
Options extends ReplaceOptions,
|
||||
Options extends Required<ReplaceOptions>,
|
||||
Accumulator extends string = '',
|
||||
> = Search extends string // For distributing `Search`
|
||||
? Replacement extends string // For distributing `Replacement`
|
||||
|
||||
8
source/screaming-snake-case.d.ts
vendored
8
source/screaming-snake-case.d.ts
vendored
@ -1,3 +1,5 @@
|
||||
import type {DefaultDelimiterCaseOptions} from './delimiter-case';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {SnakeCase} from './snake-case';
|
||||
import type {WordsOptions} from './words';
|
||||
|
||||
@ -20,5 +22,7 @@ const someVariableNoSplitOnNumbers: ScreamingSnakeCase<'p2pNetwork', {splitOnNum
|
||||
*/
|
||||
export type ScreamingSnakeCase<
|
||||
Value,
|
||||
Options extends WordsOptions = {splitOnNumbers: false},
|
||||
> = Value extends string ? Uppercase<SnakeCase<Value, Options>> : Value;
|
||||
Options extends WordsOptions = {},
|
||||
> = Value extends string
|
||||
? Uppercase<SnakeCase<Value, ApplyDefaultOptions<WordsOptions, DefaultDelimiterCaseOptions, Options>>>
|
||||
: Value;
|
||||
|
||||
10
source/set-field-type.d.ts
vendored
10
source/set-field-type.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {Simplify} from './simplify';
|
||||
|
||||
type SetFieldTypeOptions = {
|
||||
@ -11,6 +12,10 @@ type SetFieldTypeOptions = {
|
||||
preservePropertyModifiers?: boolean;
|
||||
};
|
||||
|
||||
type DefaultSetFieldTypeOptions = {
|
||||
preservePropertyModifiers: true;
|
||||
};
|
||||
|
||||
/**
|
||||
Create a type that changes the type of the given keys.
|
||||
|
||||
@ -48,7 +53,10 @@ type MyModelApi = SetFieldType<MyModel, 'createdAt' | 'updatedAt', string, {pres
|
||||
|
||||
@category Object
|
||||
*/
|
||||
export type SetFieldType<BaseType, Keys extends keyof BaseType, NewType, Options extends SetFieldTypeOptions = {preservePropertyModifiers: true}> =
|
||||
export type SetFieldType<BaseType, Keys extends keyof BaseType, NewType, Options extends SetFieldTypeOptions = {}> =
|
||||
_SetFieldType<BaseType, Keys, NewType, ApplyDefaultOptions<SetFieldTypeOptions, DefaultSetFieldTypeOptions, Options>>;
|
||||
|
||||
type _SetFieldType<BaseType, Keys extends keyof BaseType, NewType, Options extends Required<SetFieldTypeOptions>> =
|
||||
Simplify<{
|
||||
[P in keyof BaseType]: P extends Keys ? NewType : BaseType[P];
|
||||
} & (
|
||||
|
||||
34
source/shared-union-fields-deep.d.ts
vendored
34
source/shared-union-fields-deep.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
import type {NonRecursiveType, UnionMin, UnionMax, TupleLength, StaticPartOfArray, VariablePartOfArray, IsUnion, IsArrayReadonly, SetArrayAccess} from './internal';
|
||||
import type {NonRecursiveType, UnionMin, UnionMax, TupleLength, StaticPartOfArray, VariablePartOfArray, IsUnion, IsArrayReadonly, SetArrayAccess, ApplyDefaultOptions} from './internal';
|
||||
import type {IsNever} from './is-never';
|
||||
import type {UnknownArray} from './unknown-array';
|
||||
|
||||
@ -16,6 +16,10 @@ export type SharedUnionFieldsDeepOptions = {
|
||||
recurseIntoArrays?: boolean;
|
||||
};
|
||||
|
||||
type DefaultSharedUnionFieldsDeepOptions = {
|
||||
recurseIntoArrays: false;
|
||||
};
|
||||
|
||||
/**
|
||||
Create a type with shared fields from a union of object types, deeply traversing nested structures.
|
||||
|
||||
@ -82,24 +86,26 @@ function displayPetInfo(petInfo: SharedUnionFieldsDeep<Cat | Dog>['info']) {
|
||||
@category Object
|
||||
@category Union
|
||||
*/
|
||||
export type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {recurseIntoArrays: false}> =
|
||||
export type SharedUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions = {}> =
|
||||
ApplyDefaultOptions<SharedUnionFieldsDeepOptions, DefaultSharedUnionFieldsDeepOptions, Options> extends infer OptionsWithDefaults extends Required<SharedUnionFieldsDeepOptions>
|
||||
// `Union extends` will convert `Union`
|
||||
// to a [distributive conditionaltype](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
|
||||
// But this is not what we want, so we need to wrap `Union` with `[]` to prevent it.
|
||||
[Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
|
||||
? Union
|
||||
: [Union] extends [UnknownArray]
|
||||
? Options['recurseIntoArrays'] extends true
|
||||
? SetArrayAccess<SharedArrayUnionFieldsDeep<Union, Options>, IsArrayReadonly<Union>>
|
||||
: Union
|
||||
: [Union] extends [object]
|
||||
? SharedObjectUnionFieldsDeep<Union, Options>
|
||||
: Union;
|
||||
? [Union] extends [NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>]
|
||||
? Union
|
||||
: [Union] extends [UnknownArray]
|
||||
? OptionsWithDefaults['recurseIntoArrays'] extends true
|
||||
? SetArrayAccess<SharedArrayUnionFieldsDeep<Union, OptionsWithDefaults>, IsArrayReadonly<Union>>
|
||||
: Union
|
||||
: [Union] extends [object]
|
||||
? SharedObjectUnionFieldsDeep<Union, OptionsWithDefaults>
|
||||
: Union
|
||||
: never;
|
||||
|
||||
/**
|
||||
Same as `SharedUnionFieldsDeep`, but accepts only `object`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
|
||||
*/
|
||||
type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOptions> =
|
||||
type SharedObjectUnionFieldsDeep<Union, Options extends Required<SharedUnionFieldsDeepOptions>> =
|
||||
// `keyof Union` can extract the same key in union type, if there is no same key, return never.
|
||||
keyof Union extends infer Keys
|
||||
? IsNever<Keys> extends false
|
||||
@ -119,7 +125,7 @@ type SharedObjectUnionFieldsDeep<Union, Options extends SharedUnionFieldsDeepOpt
|
||||
/**
|
||||
Same as `SharedUnionFieldsDeep`, but accepts only `UnknownArray`s and as inputs. Internal helper for `SharedUnionFieldsDeep`.
|
||||
*/
|
||||
type SharedArrayUnionFieldsDeep<Union extends UnknownArray, Options extends SharedUnionFieldsDeepOptions> =
|
||||
type SharedArrayUnionFieldsDeep<Union extends UnknownArray, Options extends Required<SharedUnionFieldsDeepOptions>> =
|
||||
// Restore the readonly modifier of the array.
|
||||
SetArrayAccess<
|
||||
InternalSharedArrayUnionFieldsDeep<Union, Options>,
|
||||
@ -131,7 +137,7 @@ Internal helper for `SharedArrayUnionFieldsDeep`. Needn't care the `readonly` mo
|
||||
*/
|
||||
type InternalSharedArrayUnionFieldsDeep<
|
||||
Union extends UnknownArray,
|
||||
Options extends SharedUnionFieldsDeepOptions,
|
||||
Options extends Required<SharedUnionFieldsDeepOptions>,
|
||||
ResultTuple extends UnknownArray = [],
|
||||
> =
|
||||
// We should build a minimum possible length tuple where each element in the tuple exists in the union tuple.
|
||||
|
||||
7
source/snake-case.d.ts
vendored
7
source/snake-case.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type {DelimiterCase} from './delimiter-case';
|
||||
import type {DefaultDelimiterCaseOptions, DelimiterCase} from './delimiter-case';
|
||||
import type {ApplyDefaultOptions} from './internal';
|
||||
import type {WordsOptions} from './words';
|
||||
|
||||
/**
|
||||
@ -39,5 +40,5 @@ const dbResult: SnakeCasedProperties<ModelProps> = {
|
||||
*/
|
||||
export type SnakeCase<
|
||||
Value,
|
||||
Options extends WordsOptions = {splitOnNumbers: false},
|
||||
> = DelimiterCase<Value, '_', Options>;
|
||||
Options extends WordsOptions = {},
|
||||
> = DelimiterCase<Value, '_', ApplyDefaultOptions<WordsOptions, DefaultDelimiterCaseOptions, Options>>;
|
||||
|
||||
7
source/split.d.ts
vendored
7
source/split.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import type {And} from './and';
|
||||
import type {Not} from './internal';
|
||||
import type {ApplyDefaultOptions, Not} from './internal';
|
||||
import type {IsStringLiteral} from './is-literal';
|
||||
import type {Or} from './or';
|
||||
|
||||
@ -65,9 +65,8 @@ export type Split<
|
||||
S extends string,
|
||||
Delimiter extends string,
|
||||
Options extends SplitOptions = {},
|
||||
> = SplitHelper<S, Delimiter, {
|
||||
strictLiteralChecks: Options['strictLiteralChecks'] extends boolean ? Options['strictLiteralChecks'] : DefaultSplitOptions['strictLiteralChecks'];
|
||||
}>;
|
||||
> =
|
||||
SplitHelper<S, Delimiter, ApplyDefaultOptions<SplitOptions, DefaultSplitOptions, Options>>;
|
||||
|
||||
type SplitHelper<
|
||||
S extends string,
|
||||
|
||||
8
source/words.d.ts
vendored
8
source/words.d.ts
vendored
@ -1,4 +1,5 @@
|
||||
import type {
|
||||
ApplyDefaultOptions,
|
||||
IsLowerCase,
|
||||
IsNumeric,
|
||||
IsUpperCase,
|
||||
@ -37,7 +38,7 @@ export type WordsOptions = {
|
||||
splitOnNumbers?: boolean;
|
||||
};
|
||||
|
||||
type DefaultOptions = {
|
||||
export type DefaultWordsOptions = {
|
||||
splitOnNumbers: true;
|
||||
};
|
||||
|
||||
@ -74,9 +75,8 @@ type Words5 = Words<'p2pNetwork', {splitOnNumbers: false}>;
|
||||
@category Change case
|
||||
@category Template literal
|
||||
*/
|
||||
export type Words<Sentence extends string, Options extends WordsOptions = {}> = WordsImplementation<Sentence, {
|
||||
splitOnNumbers: Options['splitOnNumbers'] extends boolean ? Options['splitOnNumbers'] : DefaultOptions['splitOnNumbers'];
|
||||
}>;
|
||||
export type Words<Sentence extends string, Options extends WordsOptions = {}> =
|
||||
WordsImplementation<Sentence, ApplyDefaultOptions<WordsOptions, DefaultWordsOptions, Options>>;
|
||||
|
||||
type WordsImplementation<
|
||||
Sentence extends string,
|
||||
|
||||
72
test-d/internal/apply-default-options.ts
Normal file
72
test-d/internal/apply-default-options.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import {expectType} from 'tsd';
|
||||
import type {ApplyDefaultOptions} from '../../source/internal';
|
||||
|
||||
type PathsOptions = {
|
||||
maxRecursionDepth?: number;
|
||||
bracketNotation?: boolean;
|
||||
leavesOnly?: boolean;
|
||||
depth?: number;
|
||||
};
|
||||
|
||||
type DefaultPathsOptions = {
|
||||
maxRecursionDepth: 10;
|
||||
bracketNotation: false;
|
||||
leavesOnly: false;
|
||||
depth: number;
|
||||
};
|
||||
|
||||
declare const noOptionsSpecified: ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, {}>;
|
||||
expectType<DefaultPathsOptions>(noOptionsSpecified);
|
||||
|
||||
declare const someOptionsSpecified: ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, {leavesOnly: true; depth: 2}>;
|
||||
expectType<{maxRecursionDepth: 10; bracketNotation: false; leavesOnly: true; depth: 2}>(someOptionsSpecified);
|
||||
|
||||
declare const someOptionsSpecified2: ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, {maxRecursionDepth: 5}>;
|
||||
expectType<{maxRecursionDepth: 5; bracketNotation: false; leavesOnly: false; depth: number}>(someOptionsSpecified2);
|
||||
|
||||
declare const allOptionsSpecified: ApplyDefaultOptions<
|
||||
PathsOptions, DefaultPathsOptions, {maxRecursionDepth: 5; bracketNotation: false; leavesOnly: false; depth: 1}
|
||||
>;
|
||||
expectType<{maxRecursionDepth: 5; bracketNotation: false; leavesOnly: false; depth: 1}>(allOptionsSpecified);
|
||||
|
||||
declare const requiredOptions: ApplyDefaultOptions<{fixedLengthOnly?: boolean; strict: boolean}, {fixedLengthOnly: false}, {strict: true}>;
|
||||
expectType<{fixedLengthOnly: false; strict: true}>(requiredOptions);
|
||||
|
||||
// @ts-ignore
|
||||
declare const undefinedsGetOverwritten: ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, {maxRecursionDepth: undefined}>; // Possible when `exactOptionalPropertyTypes` is disabled
|
||||
expectType<DefaultPathsOptions>(undefinedsGetOverwritten);
|
||||
|
||||
// Caveat: User specified `undefined` for optional properties with explicit undefined also gets overwritten
|
||||
declare const undefinedsGetOverwritten2: ApplyDefaultOptions<{recurseIntoArrays?: boolean | undefined}, {recurseIntoArrays: true}, {recurseIntoArrays: undefined}>;
|
||||
expectType<{recurseIntoArrays: true}>(undefinedsGetOverwritten2);
|
||||
|
||||
declare const undefinedAsValidValue: ApplyDefaultOptions<{recurseIntoArrays: boolean | undefined}, {}, {recurseIntoArrays: undefined}>;
|
||||
expectType<{recurseIntoArrays: undefined}>(undefinedAsValidValue);
|
||||
|
||||
declare const optionalOptionsGetOverwritten: ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, {maxRecursionDepth?: 5; bracketNotation?: true}>;
|
||||
expectType<DefaultPathsOptions>(optionalOptionsGetOverwritten);
|
||||
|
||||
declare const neverAsOptionsGetOverwritten: ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, never>;
|
||||
expectType<DefaultPathsOptions>(neverAsOptionsGetOverwritten);
|
||||
|
||||
declare const anyAsOptionsGetOverwritten: ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, any>;
|
||||
expectType<DefaultPathsOptions>(anyAsOptionsGetOverwritten);
|
||||
|
||||
// @ts-expect-error - `Defaults` should be compatible with `Options`
|
||||
declare const defaultsShouldBeCompatible: ApplyDefaultOptions<{fixedLengthOnly?: boolean}, {fixedLengthOnly: 'no'}, {}>;
|
||||
|
||||
// @ts-expect-error - `SpecifiedOptions` should be compatible with `Options`
|
||||
declare const specifiedOptionsShouldBeCompatible: ApplyDefaultOptions<{fixedLengthOnly?: boolean}, {fixedLengthOnly: false}, {fixedLengthOnly: 'yes'}>;
|
||||
|
||||
// @ts-expect-error - Optional options should have a default value
|
||||
declare const defaultForOptionalOptions: ApplyDefaultOptions<PathsOptions, Omit<DefaultPathsOptions, 'depth'>, {}>;
|
||||
|
||||
// @ts-expect-error - Required options should be specified
|
||||
declare const requiredOptionsShouldBeSpecified: ApplyDefaultOptions<{fixedLengthOnly: boolean}, {}, {}>;
|
||||
|
||||
// @ts-expect-error - Required options should not have a default value
|
||||
declare const noDefaultForRequiredOptions: ApplyDefaultOptions<{fixedLengthOnly: boolean}, {fixedLengthOnly: false}, {fixedLengthOnly: false}>;
|
||||
|
||||
// The output of `ApplyDefaultOptions<SomeOption, ...>` should be assignable to `Required<SomeOption>`
|
||||
type SomeType<Options extends PathsOptions = {}> = _SomeType<ApplyDefaultOptions<PathsOptions, DefaultPathsOptions, Options>>;
|
||||
type _SomeType<Options extends Required<PathsOptions>> = Options;
|
||||
Loading…
x
Reference in New Issue
Block a user