diff --git a/package-lock.json b/package-lock.json index cdb12040..b2489f13 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "augment-vir", - "version": "3.0.1", + "version": "3.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "augment-vir", - "version": "3.0.1", + "version": "3.0.2", "license": "MIT", "dependencies": { "@type-challenges/utils": "^0.1.1", diff --git a/package.json b/package.json index a2fefd17..4624a7f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "augment-vir", - "version": "3.0.1", + "version": "3.0.2", "homepage": "https://github.com/electrovir/augment-vir", "bugs": { "url": "https://github.com/electrovir/augment-vir/issues" diff --git a/src/augments/object.test.ts b/src/augments/object.test.ts index 5113200b..1467385e 100644 --- a/src/augments/object.test.ts +++ b/src/augments/object.test.ts @@ -258,6 +258,9 @@ describe(typedHasProperty.name, () => { const idkWhatThisIs: unknown = (() => {}) as unknown; if (typedHasProperty(idkWhatThisIs, 'name')) { idkWhatThisIs.name; + if (typedHasProperty(idkWhatThisIs, 'derp')) { + idkWhatThisIs.derp; + } } else { // @ts-expect-error idkWhatThisIs.name; @@ -265,7 +268,7 @@ describe(typedHasProperty.name, () => { }); it('should preserve property value type when it exists', () => { - const whatever = {} as {name: string} | string; + const whatever = {} as {name: string} | string | {derp: string}; // should not be able to access the property directly // @ts-expect-error @@ -300,6 +303,38 @@ describe(typedHasProperty.name, () => { } } }); + + it('should allow type narrowing', () => { + function assertOutputProperty( + keyPath: string, + testExpectations: object, + outputKey: string, + ): void { + if (!typedHasProperty(testExpectations, outputKey)) { + throw new Error(`${keyPath} > ${outputKey} is missing.`); + } + + const value = testExpectations[outputKey]; + + if (typeof value !== 'string' && !isObject(value)) { + throw new Error(`${keyPath} > "${outputKey}" is invalid. Got "${value}"`); + } else if (isObject(value)) { + if (!typedHasProperty(value, 'type') || value.type !== 'regexp') { + throw new Error( + `${keyPath} > "${outputKey}".type is invalid. Expected "regexp".`, + ); + } + + value; + + if (!typedHasProperty(value, 'value') || typeof value.value !== 'string') { + throw new Error( + `${keyPath} > "${outputKey}".value is invalid. Expected a string.`, + ); + } + } + } + }); }); describe(typedHasProperties.name, () => { diff --git a/src/augments/object.ts b/src/augments/object.ts index d8cdd0c7..a1c51934 100644 --- a/src/augments/object.ts +++ b/src/augments/object.ts @@ -72,17 +72,17 @@ export function getObjectTypedValues( ) as ObjectGeneric[keyof ObjectGeneric][]; } -type CombineTypeWithKey< +type CombinedParentValue< KeyGeneric extends PropertyKey, ParentGeneric, -> = ParentGeneric extends Partial> - ? ParentGeneric & RequiredBy - : ParentGeneric extends - | Record - | Partial> - | {} - ? Extract, KeyGeneric>> - : ParentGeneric & Record; +> = KeyGeneric extends keyof ParentGeneric + ? RequiredBy[KeyGeneric] + : KeyGeneric extends keyof Extract> + ? RequiredBy>, KeyGeneric>[KeyGeneric] + : unknown; + +type CombineTypeWithKey = ParentGeneric & + RequiredBy>, KeyGeneric>; export function typedHasProperty( inputObject: ParentGeneric, diff --git a/src/augments/type-test.test.ts b/src/augments/type-test.test.ts new file mode 100644 index 00000000..0e6c1fdd --- /dev/null +++ b/src/augments/type-test.test.ts @@ -0,0 +1,12 @@ +import {describe, it} from 'mocha'; +import {DoesExtend, ExpectFalse, ExpectTrue} from './type-test'; + +describe('DoesExtend', () => { + it('should work on types', () => { + type one = ExpectTrue>>; + type two = ExpectFalse, unknown>>; + // type three = ExpectFalse, {name: string} | string>>; + type four = ExpectTrue>>; + type five = ExpectTrue>>; + }); +});