Comparing version 2.5.3 to 2.5.4
@@ -8,2 +8,8 @@ /** | ||
/** | ||
* Return type of calling `idx()`. `idx` always returns an optional value | ||
* @template T Value can be null or undefined | ||
*/ | ||
export type IDXOptional<T> = T | null | undefined; | ||
/** | ||
* DeepRequiredObject | ||
@@ -37,5 +43,19 @@ * Nested object condition handler | ||
* UnboxDeepRequired | ||
* Unbox type wraped with DeepRequired | ||
* Unbox type wrapped with DeepRequired | ||
*/ | ||
type UnboxDeepRequired<T> = T extends DeepRequired<infer R> ? R : T; | ||
type UnboxDeepRequired<T> = T extends string | ||
? string | ||
: T extends number | ||
? number | ||
: T extends boolean | ||
? boolean | ||
: T extends symbol | ||
? symbol | ||
: T extends bigint | ||
? bigint | ||
: T extends DeepRequiredArray<infer R> | ||
? Array<R> | ||
: T extends (...args: infer A) => DeepRequired<infer R> | ||
? (...args: A) => UnboxDeepRequired<R> | ||
: T extends DeepRequiredObject<infer R> ? R : T; | ||
@@ -78,3 +98,4 @@ /** | ||
accessor: (prop: NonNullable<DeepRequired<T1>>) => T2, | ||
): UnboxDeepRequired<T2> | null | undefined; | ||
): IDXOptional<UnboxDeepRequired<T2>>; | ||
export default idx; |
@@ -1,86 +0,76 @@ | ||
import idx from './idx'; | ||
import idx, {IDXOptional} from './idx'; | ||
interface DeepStructure { | ||
/** | ||
* Test functions are not run in runtime. They are only type checked with | ||
* TypeScript compiler | ||
*/ | ||
declare function it(description: string, test: () => void): void; | ||
interface Item<T = any> { | ||
t?: T; | ||
inner?: { | ||
item?: string; | ||
}; | ||
} | ||
interface DeepStructure<T = any> { | ||
str?: string; | ||
undef?: undefined; | ||
null?: null; | ||
generic?: T; | ||
arr?: {inner?: string}[]; | ||
foo?: { | ||
bar?: { | ||
baz?: { | ||
arr?: Array<{ | ||
inner?: { | ||
item?: string; | ||
}; | ||
}>; | ||
arr?: Item<T>[]; | ||
}; | ||
}; | ||
}; | ||
requiredInner?: { | ||
inner: boolean; | ||
}; | ||
method?(): {optional?: {member?: Item<T>}}; | ||
args?(a: string, b: number, c?: boolean): Item<T>; | ||
requiredReturnType?(): {inner: number}; | ||
} | ||
let deep: DeepStructure = {} as any; | ||
let deep: DeepStructure = {}; | ||
let item: string | undefined | null = idx( | ||
deep, | ||
_ => _.foo.bar.baz.arr[0].inner.item, | ||
); | ||
it('can access deep properties without null type assertion', () => { | ||
let str: IDXOptional<string> = idx(deep, _ => _.str); | ||
let undef: undefined | null = idx(deep, _ => _.undef); | ||
let null_: undefined | null = idx(deep, _ => _.null); | ||
let arr: IDXOptional<Item[]> = idx(deep, _ => _.foo.bar.baz.arr); | ||
}); | ||
let baz = idx(deep, _ => _.foo.bar.baz); | ||
item = idx(baz, _ => _.arr[0].inner.item); | ||
it('can call deep methods without null type assertion', () => { | ||
let member: IDXOptional<Item> = idx(deep, _ => _.method().optional.member); | ||
member = idx(deep, _ => _.args('', 1, true)); | ||
member = idx(deep, _ => _.args('', 1)); | ||
}); | ||
let listOfDeep: DeepStructure[] = []; | ||
it('can tap into optional structures (array and objects)', () => { | ||
let str: IDXOptional<string> = idx( | ||
deep, | ||
_ => _.foo.bar.baz.arr[0].inner.item, | ||
); | ||
}); | ||
item = idx(listOfDeep, _ => _[0].foo.bar.baz.arr[0].inner.item); | ||
it('returns optional object while maintaining the original type of the object structure', () => { | ||
let req = idx(deep, _ => _.requiredInner); | ||
if (req) { | ||
req.inner.valueOf(); // can safely call because inner is not optional | ||
} | ||
}); | ||
interface NullableStructure { | ||
foo: { | ||
bar: { | ||
baz: string | null; | ||
} | null; | ||
} | null; | ||
} | ||
it('returns optional array while maintaining the original type of array item type', () => { | ||
// inner property type did not become `string | null | undefined` | ||
let arr: IDXOptional<Array<{inner?: string}>> = idx(deep, _ => _.arr); | ||
}); | ||
let nullable: NullableStructure = {} as any; | ||
let bazz: string | null | undefined = idx(nullable, _ => _.foo.bar.baz); | ||
interface WithMethods<T = any> { | ||
foo?: { | ||
bar?(): number; | ||
}; | ||
baz?: { | ||
fn?(): {inner?: string}; | ||
}; | ||
args?(a: number): number; | ||
manyArgs?( | ||
a: number, | ||
b: string, | ||
c: boolean, | ||
d: number, | ||
e: number, | ||
f: number, | ||
g: string, | ||
h: string, | ||
k: number, | ||
l: boolean, | ||
m: string, | ||
): number; | ||
restArgs?(...args: string[]): string; | ||
genrric?(arg: T): T; | ||
} | ||
let withMethods: WithMethods<boolean> = {} as any; | ||
let n: number | undefined | null = idx(withMethods, _ => _.foo.bar()); | ||
n = idx(withMethods, _ => _.args(1)); | ||
n = idx(withMethods, _ => | ||
_.manyArgs(1, 'b', true, 1, 2, 3, '4', '5', 1, true, ''), | ||
); | ||
let s: string | undefined | null = idx(withMethods, _ => _.baz.fn().inner); | ||
s = idx(withMethods, _ => _.restArgs('1', '2', '3', '4', '5', '6')); | ||
let b: boolean | undefined | null = idx(withMethods, _ => _.genrric(true)); | ||
let foo = idx(withMethods, _ => _.foo); | ||
// foo should be { bar?(): number } | ||
let fooTest1: typeof foo = {}; | ||
let fooTest2: typeof foo = { | ||
bar(): number { | ||
return 1; | ||
}, | ||
}; | ||
it('maintains the return type of method calls', () => { | ||
let req = idx(deep, _ => _.requiredReturnType()); | ||
if (req) { | ||
req.inner.toFixed(); // can safely call because inner is not optional | ||
} | ||
}); |
{ | ||
"name": "idx", | ||
"version": "2.5.3", | ||
"version": "2.5.4", | ||
"description": "Utility function for traversing properties on objects and arrays.", | ||
@@ -31,3 +31,3 @@ "main": "lib/idx.js", | ||
}, | ||
"gitHead": "44866f559394971e7a4b354df4ac6166ac2e756d" | ||
"gitHead": "361d07e4979cf7b2b53ad79481411dc1b11dc96a" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
12403
7
239