Skip to content

Commit

Permalink
Merge branch 'main' into fix-camel-cased-properties-deep
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghost-str committed Jun 17, 2024
2 parents 8d389f1 + 28efb29 commit 508830f
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 39 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "type-fest",
"version": "4.20.0",
"version": "4.20.1",
"description": "A collection of essential TypeScript types",
"license": "(MIT OR CC0-1.0)",
"repository": "sindresorhus/type-fest",
Expand Down Expand Up @@ -47,6 +47,7 @@
},
"xo": {
"rules": {
"@typescript-eslint/no-extraneous-class": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/ban-types": "off",
"@typescript-eslint/naming-convention": "off",
Expand Down
22 changes: 14 additions & 8 deletions source/paths.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import type {EmptyObject} from './empty-object';
import type {IsAny} from './is-any';
import type {IsNever} from './is-never';
import type {UnknownArray} from './unknown-array';
import type {Sum} from './sum';
import type {LessThan} from './less-than';

/**
Generate a union of all possible paths to properties in the given object.
Expand Down Expand Up @@ -45,22 +47,24 @@ open('listB.1'); // TypeError. Because listB only has one element.
@category Object
@category Array
*/
export type Paths<T> =
export type Paths<T> = Paths_<T>;

type Paths_<T, Depth extends number = 0> =
T extends NonRecursiveType | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown>
? never
: IsAny<T> extends true
? never
: T extends UnknownArray
? number extends T['length']
// We need to handle the fixed and non-fixed index part of the array separately.
? InternalPaths<StaticPartOfArray<T>>
| InternalPaths<Array<VariablePartOfArray<T>[number]>>
: InternalPaths<T>
? InternalPaths<StaticPartOfArray<T>, Depth>
| InternalPaths<Array<VariablePartOfArray<T>[number]>, Depth>
: InternalPaths<T, Depth>
: T extends object
? InternalPaths<T>
? InternalPaths<T, Depth>
: never;

export type InternalPaths<_T, T = Required<_T>> =
export type InternalPaths<_T, Depth extends number = 0, T = Required<_T>> =
T extends EmptyObject | readonly []
? never
: {
Expand All @@ -71,8 +75,10 @@ export type InternalPaths<_T, T = Required<_T>> =
| Key
| ToString<Key>
| (
IsNever<Paths<T[Key]>> extends false
? `${Key}.${Paths<T[Key]>}`
LessThan<Depth, 15> extends true // Limit the depth to prevent infinite recursion
? IsNever<Paths_<T[Key], Sum<Depth, 1>>> extends false
? `${Key}.${Paths_<T[Key], Sum<Depth, 1>>}`
: never
: never
)
: never
Expand Down
24 changes: 12 additions & 12 deletions source/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,25 @@ export type Schema<ObjectType, ValueType> = ObjectType extends string
? ValueType
: ObjectType extends ReadonlySet<unknown>
? ValueType
: ObjectType extends readonly unknown[]
? ValueType
: ObjectType extends unknown[]
: ObjectType extends Array<infer U>
? Array<Schema<U, ValueType>>
: ObjectType extends (...arguments_: unknown[]) => unknown
? ValueType
: ObjectType extends (...arguments_: unknown[]) => unknown
: ObjectType extends Date
? ValueType
: ObjectType extends Date
: ObjectType extends Function
? ValueType
: ObjectType extends Function
: ObjectType extends RegExp
? ValueType
: ObjectType extends RegExp
? ValueType
: ObjectType extends object
? SchemaObject<ObjectType, ValueType>
: ValueType;
: ObjectType extends object
? SchemaObject<ObjectType, ValueType>
: ValueType;

/**
Same as `Schema`, but accepts only `object`s as inputs. Internal helper for `Schema`.
*/
type SchemaObject<ObjectType extends object, K> = {
[KeyType in keyof ObjectType]: Schema<ObjectType[KeyType], K> | K;
[KeyType in keyof ObjectType]: ObjectType[KeyType] extends readonly unknown[] | unknown[]
? Schema<ObjectType[KeyType], K>
: Schema<ObjectType[KeyType], K> | K;
};
14 changes: 12 additions & 2 deletions test-d/paths.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expectType} from 'tsd';
import type {Paths} from '../index';
import {expectAssignable, expectType} from 'tsd';
import type {Paths, PickDeep} from '../index';

declare const normal: Paths<{foo: string}>;
expectType<'foo'>(normal);
Expand Down Expand Up @@ -98,3 +98,13 @@ expectType<number | `${number}` | `${number}.b` | `${number}.a`>(leadingSpreadTu

declare const leadingSpreadTuple1: Paths<[...Array<{a: string}>, {b: number}, {c: number}]>;
expectType<number | `${number}` | `${number}.b` | `${number}.c` | `${number}.a`>(leadingSpreadTuple1);

// Circularly references
type MyEntity = {
myOtherEntity?: MyOtherEntity;
};
type MyOtherEntity = {
myEntity?: MyEntity;
};
type MyEntityPaths = Paths<MyEntity>;
expectAssignable<string>({} as MyEntityPaths);
37 changes: 21 additions & 16 deletions test-d/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const foo = {
set: new Set<string>(),
array: ['foo'],
tuple: ['foo'] as ['foo'],
objectArray: [{key: 'value'}],
readonlyMap: new Map<string, string>() as ReadonlyMap<string, string>,
readonlySet: new Set<string>() as ReadonlySet<string>,
readonlyArray: ['foo'] as readonly string[],
Expand All @@ -36,12 +37,13 @@ const fooSchema: FooSchema = {
symbol: 'A',
map: 'A',
set: 'A',
array: 'A',
tuple: 'A',
array: ['A'],
tuple: ['A'],
objectArray: [{key: 'A'}],
readonlyMap: 'A',
readonlySet: 'A',
readonlyArray: 'A',
readonlyTuple: 'A',
readonlyArray: ['A'] as const,
readonlyTuple: ['A'] as const,
regExp: 'A',
},
};
Expand All @@ -60,12 +62,13 @@ expectType<FooOption>(barSchema.boolean);
expectType<FooOption>(barSchema.symbol);
expectType<FooOption>(barSchema.map);
expectType<FooOption>(barSchema.set);
expectType<FooOption>(barSchema.array);
expectType<FooOption>(barSchema.tuple);
expectType<FooOption[]>(barSchema.array);
expectType<FooOption[]>(barSchema.tuple);
expectType<Array<{key: FooOption}>>(barSchema.objectArray);
expectType<FooOption>(barSchema.readonlyMap);
expectType<FooOption>(barSchema.readonlySet);
expectType<FooOption>(barSchema.readonlyArray);
expectType<FooOption>(barSchema.readonlyTuple);
expectType<readonly FooOption[]>(barSchema.readonlyArray);
expectType<readonly [FooOption]>(barSchema.readonlyTuple);
expectType<FooOption>(barSchema.regExp);

type ComplexOption = {
Expand All @@ -92,12 +95,13 @@ const complexFoo: ComplexSchema = {
symbol: createComplexOption('readonly'),
map: createComplexOption('readonly'),
set: createComplexOption('readonly'),
array: createComplexOption('readonly'),
tuple: createComplexOption('readonly'),
array: [createComplexOption('readonly')],
tuple: [createComplexOption('readonly')],
objectArray: [{key: createComplexOption('readonly')}],
readonlyMap: createComplexOption('readonly'),
readonlySet: createComplexOption('readonly'),
readonlyArray: createComplexOption('readonly'),
readonlyTuple: createComplexOption('readonly'),
readonlyArray: [createComplexOption('readonly')] as const,
readonlyTuple: [createComplexOption('readonly')] as const,
regExp: createComplexOption('readonly'),
},
};
Expand All @@ -114,10 +118,11 @@ expectType<ComplexOption>(complexBarSchema.boolean);
expectType<ComplexOption>(complexBarSchema.symbol);
expectType<ComplexOption>(complexBarSchema.map);
expectType<ComplexOption>(complexBarSchema.set);
expectType<ComplexOption>(complexBarSchema.array);
expectType<ComplexOption>(complexBarSchema.tuple);
expectType<ComplexOption[]>(complexBarSchema.array);
expectType<ComplexOption[]>(complexBarSchema.tuple);
expectType<Array<{key: ComplexOption}>>(complexBarSchema.objectArray);
expectType<ComplexOption>(complexBarSchema.readonlyMap);
expectType<ComplexOption>(complexBarSchema.readonlySet);
expectType<ComplexOption>(complexBarSchema.readonlyArray);
expectType<ComplexOption>(complexBarSchema.readonlyTuple);
expectType<readonly ComplexOption[]>(complexBarSchema.readonlyArray);
expectType<readonly [ComplexOption]>(complexBarSchema.readonlyTuple);
expectType<ComplexOption>(complexBarSchema.regExp);

0 comments on commit 508830f

Please sign in to comment.