diff --git a/README.md b/README.md index b148ed7..83b09fe 100644 --- a/README.md +++ b/README.md @@ -428,6 +428,19 @@ const f = (a: number) => [a, a] expectTypeOf(f).toBeCallableWith('foo') ``` +Use `.map` to transform types: + +This can be useful for generic functions or complex types which you can't access via `.toBeCallableWith`, `.toHaveProperty` etc. The callback function isn't called at runtime, which can make this a useful way to get complex inferred types without worrying about running code. + +```typescript +const capitalize = (input: S) => + (input.slice(0, 1).toUpperCase() + input.slice(1)) as Capitalize + +expectTypeOf(capitalize) + .map(fn => fn('hello world')) + .toEqualTypeOf<'Hello world'>() +``` + You can also check type guards & type assertions: ```typescript diff --git a/src/index.ts b/src/index.ts index a9c1d7c..410d55f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -498,6 +498,14 @@ export interface BaseExpectTypeOf { */ toBeNullable: Scolder, Options> + /** + * Transform that type of the value via a callback. + * + * @param fn A callback that transforms the input value. Note that this function is not actually called - it's only used for type inference. + * @returns A new type which can be used for further assertions. + */ + map: (fn: (value: Actual) => T) => ExpectTypeOf + /** * Checks whether a function is callable with the given parameters. * @@ -911,6 +919,7 @@ export const expectTypeOf: _ExpectTypeOf = ( toMatchTypeOf: fn, toEqualTypeOf: fn, toBeConstructibleWith: fn, + map: expectTypeOf, toBeCallableWith: expectTypeOf, extract: expectTypeOf, exclude: expectTypeOf, diff --git a/test/usage.test.ts b/test/usage.test.ts index a843ec0..c46696a 100644 --- a/test/usage.test.ts +++ b/test/usage.test.ts @@ -305,6 +305,19 @@ test("You can't use `.toBeCallableWith` with `.not` - you need to use ts-expect- expectTypeOf(f).toBeCallableWith('foo') }) +/** + * This can be useful for generic functions or complex types which you can't access via `.toBeCallableWith`, `.toHaveProperty` etc. + * The callback function isn't called at runtime, which can make this a useful way to get complex inferred types without worrying about running code. + */ +test('Use `.map` to transform types', () => { + const capitalize = (input: S) => + (input.slice(0, 1).toUpperCase() + input.slice(1)) as Capitalize + + expectTypeOf(capitalize) + .map(fn => fn('hello world')) + .toEqualTypeOf<'Hello world'>() +}) + test('You can also check type guards & type assertions', () => { const assertNumber = (v: any): asserts v is number => { if (typeof v !== 'number') {