From 34d6181f6c6a94cf50e3eae28dd006d6fc91ec02 Mon Sep 17 00:00:00 2001 From: mmkal Date: Mon, 30 Nov 2020 08:49:46 -0500 Subject: [PATCH 1/5] Add `.excluding` and `.extracting` helpers --- packages/expect-type/readme.md | 34 +++++++++++++++++++ .../expect-type/src/__tests__/index.test.ts | 32 +++++++++++++++++ packages/expect-type/src/index.ts | 4 +++ 3 files changed, 70 insertions(+) diff --git a/packages/expect-type/readme.md b/packages/expect-type/readme.md index 5d27889b..706fc9c8 100644 --- a/packages/expect-type/readme.md +++ b/packages/expect-type/readme.md @@ -178,6 +178,40 @@ expectTypeOf(1).not.toBeUndefined() expectTypeOf(1).not.toBeNullable() ``` +Use `.excluding` and `.extracting` to narrow down complex union types: + +```typescript +type ResponsiveProp = T | T[] | {xs?: T; sm?: T; md?: T} +const getResponsiveProp = (props: T): ResponsiveProp => [props] +type CSSProperties = {margin?: string; padding?: string} + +const cssProperties: CSSProperties = {margin: '1px', padding: '2px'} + +expectTypeOf(getResponsiveProp(cssProperties)) + .excluding() + .excluding<{xs?: unknown}>() + .toEqualTypeOf() + +expectTypeOf(getResponsiveProp(cssProperties)) + .extracting() + .toEqualTypeOf() + +expectTypeOf(getResponsiveProp(cssProperties)) + .extracting<{xs?: any}>() + .toEqualTypeOf<{xs?: CSSProperties; sm?: CSSProperties; md?: CSSProperties}>() +``` + +`.excluding` and `.extracting` return never if no types remain after exclusion: + +```typescript +type Person = {name: string; age: number} +type Customer = Person & {customerId: string} +type Employee = Person & {employeeId: string} + +expectTypeOf().excluding<{name: string}>().toBeNever() +expectTypeOf().extracting<{foo: string}>().toBeNever() +``` + Make assertions about object properties: ```typescript diff --git a/packages/expect-type/src/__tests__/index.test.ts b/packages/expect-type/src/__tests__/index.test.ts index 3c67afb0..484aeed5 100644 --- a/packages/expect-type/src/__tests__/index.test.ts +++ b/packages/expect-type/src/__tests__/index.test.ts @@ -1,5 +1,7 @@ import {expectTypeOf} from '..' +/* eslint prettier/prettier: ["warn", { "singleQuote": true, "semi": false, "arrowParens": "avoid", "trailingComma": "es5", "bracketSpacing": false, "endOfLine": "auto", "printWidth": 100 }] */ + test("Check an object's type with `.toEqualTypeOf`", () => { expectTypeOf({a: 1}).toEqualTypeOf<{a: number}>() }) @@ -96,6 +98,36 @@ test('More `.not` examples', () => { expectTypeOf(1).not.toBeNullable() }) +test('Use `.excluding` and `.extracting` to narrow down complex union types', () => { + type ResponsiveProp = T | T[] | {xs?: T; sm?: T; md?: T} + const getResponsiveProp = (props: T): ResponsiveProp => [props] + type CSSProperties = {margin?: string; padding?: string} + + const cssProperties: CSSProperties = {margin: '1px', padding: '2px'} + + expectTypeOf(getResponsiveProp(cssProperties)) + .excluding() + .excluding<{xs?: unknown}>() + .toEqualTypeOf() + + expectTypeOf(getResponsiveProp(cssProperties)) + .extracting() + .toEqualTypeOf() + + expectTypeOf(getResponsiveProp(cssProperties)) + .extracting<{xs?: any}>() + .toEqualTypeOf<{xs?: CSSProperties; sm?: CSSProperties; md?: CSSProperties}>() +}) + +test('`.excluding` and `.extracting` return never if no types remain after exclusion', () => { + type Person = {name: string; age: number} + type Customer = Person & {customerId: string} + type Employee = Person & {employeeId: string} + + expectTypeOf().excluding<{name: string}>().toBeNever() + expectTypeOf().extracting<{foo: string}>().toBeNever() +}) + test('Make assertions about object properties', () => { const obj = {a: 1, b: ''} diff --git a/packages/expect-type/src/index.ts b/packages/expect-type/src/index.ts index 77b25bf8..f1aa7b6d 100644 --- a/packages/expect-type/src/index.ts +++ b/packages/expect-type/src/index.ts @@ -103,6 +103,8 @@ export interface ExpectTypeOf { key: K, ...MISMATCH: MismatchArgs, B> ) => K extends keyof Actual ? ExpectTypeOf : true + extracting: (v?: V) => ExpectTypeOf, B> + excluding: (v?: V) => ExpectTypeOf, B> parameter: >(number: K) => ExpectTypeOf[K], B> parameters: ExpectTypeOf, B> constructorParameters: ExpectTypeOf, B> @@ -172,6 +174,8 @@ export const expectTypeOf: _ExpectTypeOf = (actual?: Actual): ExpectType toEqualTypeOf: fn, toBeCallableWith: fn, toBeConstructibleWith: fn, + extracting: expectTypeOf, + excluding: expectTypeOf, toHaveProperty: expectTypeOf, parameter: expectTypeOf, } From 5951c5722c268aa206f2f38d82b25d921ea32099 Mon Sep 17 00:00:00 2001 From: mmkal Date: Mon, 30 Nov 2020 13:56:18 +0000 Subject: [PATCH 2/5] chore: change files --- .../changes/expect-type/exclude-extract_pr-220.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/expect-type/exclude-extract_pr-220.json diff --git a/common/changes/expect-type/exclude-extract_pr-220.json b/common/changes/expect-type/exclude-extract_pr-220.json new file mode 100644 index 00000000..6957d461 --- /dev/null +++ b/common/changes/expect-type/exclude-extract_pr-220.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Add `.excluding` and `.extracting` helpers (#220)", + "type": "minor", + "packageName": "expect-type" + } + ], + "packageName": "expect-type", + "email": "mmkal@users.noreply.github.com" +} \ No newline at end of file From 21e6e71a86df577f01d009d85882b81038530615 Mon Sep 17 00:00:00 2001 From: mmkal Date: Fri, 4 Dec 2020 14:44:26 -0500 Subject: [PATCH 3/5] Make naming less weird --- packages/expect-type/src/__tests__/index.test.ts | 16 ++++++++-------- packages/expect-type/src/index.ts | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/expect-type/src/__tests__/index.test.ts b/packages/expect-type/src/__tests__/index.test.ts index c1b83cc8..aa7f9cb3 100644 --- a/packages/expect-type/src/__tests__/index.test.ts +++ b/packages/expect-type/src/__tests__/index.test.ts @@ -100,7 +100,7 @@ test('More `.not` examples', () => { expectTypeOf(1).not.toBeNullable() }) -test('Use `.excluding` and `.extracting` to narrow down complex union types', () => { +test('Use `.extract` and `.exclude` to narrow down complex union types', () => { type ResponsiveProp = T | T[] | {xs?: T; sm?: T; md?: T} const getResponsiveProp = (props: T): ResponsiveProp => [props] type CSSProperties = {margin?: string; padding?: string} @@ -108,26 +108,26 @@ test('Use `.excluding` and `.extracting` to narrow down complex union types', () const cssProperties: CSSProperties = {margin: '1px', padding: '2px'} expectTypeOf(getResponsiveProp(cssProperties)) - .excluding() - .excluding<{xs?: unknown}>() + .exclude() + .exclude<{xs?: unknown}>() .toEqualTypeOf() expectTypeOf(getResponsiveProp(cssProperties)) - .extracting() + .extract() .toEqualTypeOf() expectTypeOf(getResponsiveProp(cssProperties)) - .extracting<{xs?: any}>() + .extract<{xs?: any}>() .toEqualTypeOf<{xs?: CSSProperties; sm?: CSSProperties; md?: CSSProperties}>() }) -test('`.excluding` and `.extracting` return never if no types remain after exclusion', () => { +test('`.extract` and `.exclude` return never if no types remain after exclusion', () => { type Person = {name: string; age: number} type Customer = Person & {customerId: string} type Employee = Person & {employeeId: string} - expectTypeOf().excluding<{name: string}>().toBeNever() - expectTypeOf().extracting<{foo: string}>().toBeNever() + expectTypeOf().extract<{foo: string}>().toBeNever() + expectTypeOf().exclude<{name: string}>().toBeNever() }) test('Make assertions about object properties', () => { diff --git a/packages/expect-type/src/index.ts b/packages/expect-type/src/index.ts index 6ec46e0f..7a049fa3 100644 --- a/packages/expect-type/src/index.ts +++ b/packages/expect-type/src/index.ts @@ -104,8 +104,8 @@ export interface ExpectTypeOf { key: K, ...MISMATCH: MismatchArgs, B> ) => K extends keyof Actual ? ExpectTypeOf : true - extracting: (v?: V) => ExpectTypeOf, B> - excluding: (v?: V) => ExpectTypeOf, B> + extract: (v?: V) => ExpectTypeOf, B> + exclude: (v?: V) => ExpectTypeOf, B> parameter: >(number: K) => ExpectTypeOf[K], B> parameters: ExpectTypeOf, B> constructorParameters: ExpectTypeOf, B> @@ -176,8 +176,8 @@ export const expectTypeOf: _ExpectTypeOf = (actual?: Actual): ExpectType toEqualTypeOf: fn, toBeCallableWith: fn, toBeConstructibleWith: fn, - extracting: expectTypeOf, - excluding: expectTypeOf, + extract: expectTypeOf, + exclude: expectTypeOf, toHaveProperty: expectTypeOf, parameter: expectTypeOf, } From e2dd97c8a67e2f2f66934551baa741c565d0e0bd Mon Sep 17 00:00:00 2001 From: mmkal Date: Fri, 4 Dec 2020 21:25:32 +0000 Subject: [PATCH 4/5] chore: change files --- common/changes/expect-type/exclude-extract_pr-220.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/changes/expect-type/exclude-extract_pr-220.json b/common/changes/expect-type/exclude-extract_pr-220.json index 6957d461..e0d16e46 100644 --- a/common/changes/expect-type/exclude-extract_pr-220.json +++ b/common/changes/expect-type/exclude-extract_pr-220.json @@ -1,7 +1,7 @@ { "changes": [ { - "comment": "Add `.excluding` and `.extracting` helpers (#220)", + "comment": "Add `.exclude` and `.extract` helpers (#220)", "type": "minor", "packageName": "expect-type" } From 7637d7028158f7ae84d5b9fa5235117746197eed Mon Sep 17 00:00:00 2001 From: mmkal Date: Fri, 4 Dec 2020 16:33:14 -0500 Subject: [PATCH 5/5] Add more test cases --- packages/expect-type/readme.md | 21 +++++++++++-------- .../expect-type/src/__tests__/index.test.ts | 5 ++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/expect-type/readme.md b/packages/expect-type/readme.md index f0a2c615..138ec3a6 100644 --- a/packages/expect-type/readme.md +++ b/packages/expect-type/readme.md @@ -179,38 +179,41 @@ expectTypeOf(1).not.toBeUndefined() expectTypeOf(1).not.toBeNullable() ``` -Use `.excluding` and `.extracting` to narrow down complex union types: +Use `.extract` and `.exclude` to narrow down complex union types: ```typescript type ResponsiveProp = T | T[] | {xs?: T; sm?: T; md?: T} -const getResponsiveProp = (props: T): ResponsiveProp => [props] +const getResponsiveProp = (props: T): ResponsiveProp => ({}) type CSSProperties = {margin?: string; padding?: string} const cssProperties: CSSProperties = {margin: '1px', padding: '2px'} expectTypeOf(getResponsiveProp(cssProperties)) - .excluding() - .excluding<{xs?: unknown}>() + .exclude() + .exclude<{xs?: unknown}>() .toEqualTypeOf() expectTypeOf(getResponsiveProp(cssProperties)) - .extracting() + .extract() .toEqualTypeOf() expectTypeOf(getResponsiveProp(cssProperties)) - .extracting<{xs?: any}>() + .extract<{xs?: any}>() .toEqualTypeOf<{xs?: CSSProperties; sm?: CSSProperties; md?: CSSProperties}>() + +expectTypeOf>().exclude().toHaveProperty('sm') +expectTypeOf>().exclude().not.toHaveProperty('xxl') ``` -`.excluding` and `.extracting` return never if no types remain after exclusion: +`.extract` and `.exclude` return never if no types remain after exclusion: ```typescript type Person = {name: string; age: number} type Customer = Person & {customerId: string} type Employee = Person & {employeeId: string} -expectTypeOf().excluding<{name: string}>().toBeNever() -expectTypeOf().extracting<{foo: string}>().toBeNever() +expectTypeOf().extract<{foo: string}>().toBeNever() +expectTypeOf().exclude<{name: string}>().toBeNever() ``` Make assertions about object properties: diff --git a/packages/expect-type/src/__tests__/index.test.ts b/packages/expect-type/src/__tests__/index.test.ts index e3af7734..e6969947 100644 --- a/packages/expect-type/src/__tests__/index.test.ts +++ b/packages/expect-type/src/__tests__/index.test.ts @@ -102,7 +102,7 @@ test('More `.not` examples', () => { test('Use `.extract` and `.exclude` to narrow down complex union types', () => { type ResponsiveProp = T | T[] | {xs?: T; sm?: T; md?: T} - const getResponsiveProp = (props: T): ResponsiveProp => [props] + const getResponsiveProp = (props: T): ResponsiveProp => ({}) type CSSProperties = {margin?: string; padding?: string} const cssProperties: CSSProperties = {margin: '1px', padding: '2px'} @@ -119,6 +119,9 @@ test('Use `.extract` and `.exclude` to narrow down complex union types', () => { expectTypeOf(getResponsiveProp(cssProperties)) .extract<{xs?: any}>() .toEqualTypeOf<{xs?: CSSProperties; sm?: CSSProperties; md?: CSSProperties}>() + + expectTypeOf>().exclude().toHaveProperty('sm') + expectTypeOf>().exclude().not.toHaveProperty('xxl') }) test('`.extract` and `.exclude` return never if no types remain after exclusion', () => {