Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop tsd for tests in favor of expect-type #499

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/contributing.md
Expand Up @@ -6,7 +6,7 @@
- Please help review the other open pull requests. If there are no open pull requests, provide some feedback on some of the open issues.
- Create a new file in the `test-d` directory and write at least one type test.
- See the other tests for inspiration.
- If it makes sense, also write a negative test using [`expectNotAssignable()`](https://github.com/SamVerschueren/tsd#expectnotassignabletexpression-any) or, to test other diagnostics, [`expectError()`](https://github.com/SamVerschueren/tsd#expecterrort--anyexpression-t).
- If it makes sense, also write a negative test using [`expectTypeOf().not`](https://github.com/mmkal/expect-type#features) or, to test other diagnostics, `@ts-expect-error`.
- Don't use one-character type names like `T` and `U`. Use descriptive names. See the existing types for inspiration.
- Write a good documentation comment that includes:
- Write a short and clear description of what the type does.
Expand Down
3 changes: 1 addition & 2 deletions package.json
Expand Up @@ -15,7 +15,7 @@
"node": ">=14.16"
},
"scripts": {
"test": "xo && tsd && tsc && node script/test/source-files-extension.js"
"test": "xo && tsc && node script/test/source-files-extension.js"
},
"files": [
"index.d.ts",
Expand All @@ -36,7 +36,6 @@
"devDependencies": {
"@sindresorhus/tsconfig": "~0.7.0",
"expect-type": "^0.14.2",
"tsd": "^0.24.1",
"typescript": "^4.8.3",
"xo": "^0.52.2"
},
Expand Down
6 changes: 3 additions & 3 deletions test-d/async-return-type.ts
@@ -1,4 +1,4 @@
import {expectNotAssignable, expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {AsyncReturnType} from '../index';

async function asyncFunction(): Promise<number> {
Expand All @@ -9,6 +9,6 @@ type Value = AsyncReturnType<typeof asyncFunction>;

// eslint-disable-next-line @typescript-eslint/no-floating-promises
asyncFunction().then(value => {
expectType<Value>(value);
expectNotAssignable<string>(value);
expectTypeOf(value).toEqualTypeOf<Value>();
expectTypeOf(value).not.toMatchTypeOf<string>();
});
11 changes: 6 additions & 5 deletions test-d/asyncify.ts
@@ -1,19 +1,20 @@
import {expectType, expectError} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {Asyncify} from '../index';

declare function getFooSync(name: string): RegExp;
declare function getFooWithThisArgSync(this: Date, name: string): RegExp;

// Basic usage.
declare const getFooAsync1: Asyncify<typeof getFooSync>;
expectType<(name: string) => Promise<RegExp>>(getFooAsync1);
expectTypeOf(getFooAsync1).toEqualTypeOf<(name: string) => Promise<RegExp>>();

// Noops with async functions.
declare const getFooAsync2: Asyncify<typeof getFooAsync1>;
expectType<typeof getFooAsync1>(getFooAsync2);
expectTypeOf(getFooAsync2).toEqualTypeOf<typeof getFooAsync1>();

// Respects `thisArg`.
declare const getFooWithThisArgAsync1: Asyncify<typeof getFooWithThisArgSync>;
const callResult = getFooWithThisArgAsync1.call(new Date(), 'foo');
expectType<Promise<RegExp>>(callResult);
expectError(getFooWithThisArgAsync1.call('not-date', 'foo'));
expectTypeOf(callResult).toEqualTypeOf<Promise<RegExp>>();
// @ts-expect-error
void getFooWithThisArgAsync1.call('not-date', 'foo');
36 changes: 18 additions & 18 deletions test-d/camel-case.ts
@@ -1,52 +1,52 @@
import {expectType, expectAssignable} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {CamelCase, Split} from '../index';

// Split
const prefixSplit: Split<'--very-prefixed', '-'> = ['', '', 'very', 'prefixed'];
expectType<['', '', 'very', 'prefixed']>(prefixSplit);
expectTypeOf(prefixSplit).toEqualTypeOf<['', '', 'very', 'prefixed']>();

// CamelCase
const camelFromPascal: CamelCase<'FooBar'> = 'fooBar';
expectType<'fooBar'>(camelFromPascal);
expectTypeOf(camelFromPascal).toEqualTypeOf<'fooBar'>();

const camelFromKebab: CamelCase<'foo-bar'> = 'fooBar';
expectType<'fooBar'>(camelFromKebab);
expectTypeOf(camelFromKebab).toEqualTypeOf<'fooBar'>();

const camelFromComplexKebab: CamelCase<'foo-bar-abc-123'> = 'fooBarAbc123';
expectType<'fooBarAbc123'>(camelFromComplexKebab);
expectTypeOf(camelFromComplexKebab).toEqualTypeOf<'fooBarAbc123'>();

const camelFromSpace: CamelCase<'foo bar'> = 'fooBar';
expectType<'fooBar'>(camelFromSpace);
expectTypeOf(camelFromSpace).toEqualTypeOf<'fooBar'>();

const camelFromSnake: CamelCase<'foo_bar'> = 'fooBar';
expectType<'fooBar'>(camelFromSnake);
expectTypeOf(camelFromSnake).toEqualTypeOf<'fooBar'>();

const noDelimiterFromMono: CamelCase<'foobar'> = 'foobar';
expectType<'foobar'>(noDelimiterFromMono);
expectTypeOf(noDelimiterFromMono).toEqualTypeOf<'foobar'>();

const camelFromMixed: CamelCase<'foo-bar_abc xyzBarFoo'> = 'fooBarAbcXyzBarFoo';
expectType<'fooBarAbcXyzBarFoo'>(camelFromMixed);
expectTypeOf(camelFromMixed).toEqualTypeOf<'fooBarAbcXyzBarFoo'>();

const camelFromVendorPrefixedCssProperty: CamelCase<'-webkit-animation'> = 'webkitAnimation';
expectType<'webkitAnimation'>(camelFromVendorPrefixedCssProperty);
expectTypeOf(camelFromVendorPrefixedCssProperty).toEqualTypeOf<'webkitAnimation'>();

const camelFromDoublePrefixedKebab: CamelCase<'--very-prefixed'> = 'veryPrefixed';
expectType<'veryPrefixed'>(camelFromDoublePrefixedKebab);
expectTypeOf(camelFromDoublePrefixedKebab).toEqualTypeOf<'veryPrefixed'>();

const camelFromRepeatedSeparators: CamelCase<'foo____bar'> = 'fooBar';
expectType<'fooBar'>(camelFromRepeatedSeparators);
expectTypeOf(camelFromRepeatedSeparators).toEqualTypeOf<'fooBar'>();

const camelFromUppercase: CamelCase<'FOO'> = 'foo';
expectType<'foo'>(camelFromUppercase);
expectTypeOf(camelFromUppercase).toEqualTypeOf<'foo'>();

const camelFromLowercase: CamelCase<'foo'> = 'foo';
expectType<'foo'>(camelFromLowercase);
expectTypeOf(camelFromLowercase).toEqualTypeOf<'foo'>();

const camelFromScreamingSnakeCase: CamelCase<'FOO_BAR'> = 'fooBar';
expectType<'fooBar'>(camelFromScreamingSnakeCase);
expectTypeOf(camelFromScreamingSnakeCase).toEqualTypeOf<'fooBar'>();

const camelFromScreamingKebabCase: CamelCase<'FOO-BAR'> = 'fooBar';
expectType<'fooBar'>(camelFromScreamingKebabCase);
expectTypeOf(camelFromScreamingKebabCase).toEqualTypeOf<'fooBar'>();

// Verifying example
type CamelCasedProperties<T> = {
Expand All @@ -62,11 +62,11 @@ type RawOptions = {
'OTHER-FIELD': boolean;
};

expectAssignable<CamelCasedProperties<RawOptions>>({
expectTypeOf({
dryRun: true,
fullFamilyName: 'bar.js',
foo: 123,
bar: 'foo',
quzQux: 6,
otherField: false,
});
}).toMatchTypeOf<CamelCasedProperties<RawOptions>>();
10 changes: 5 additions & 5 deletions test-d/camel-cased-properties-deep.ts
@@ -1,15 +1,15 @@
import {expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {CamelCasedPropertiesDeep} from '../index';

declare const foo: CamelCasedPropertiesDeep<{A: {B: number; C: Array<{D: string}>}}>;

expectType<{a: {b: number; c: Array<{d: string}>}}>(foo);
expectTypeOf(foo).toEqualTypeOf<{a: {b: number; c: Array<{d: string}>}}>();

declare const fooBar: CamelCasedPropertiesDeep<() => {a: string}>;
expectType<() => {a: string}>(fooBar);
expectTypeOf(fooBar).toEqualTypeOf<() => {a: string}>();

declare const bar: CamelCasedPropertiesDeep<Set<{fooBar: string}>>;
expectType<Set<{fooBar: string}>>(bar);
expectTypeOf(bar).toEqualTypeOf<Set<{fooBar: string}>>();

// Verify example
type User = {
Expand Down Expand Up @@ -46,4 +46,4 @@ const result: CamelCasedPropertiesDeep<UserWithFriends> = {
},
],
};
expectType<CamelCasedPropertiesDeep<UserWithFriends>>(result);
expectTypeOf(result).toEqualTypeOf<CamelCasedPropertiesDeep<UserWithFriends>>();
10 changes: 5 additions & 5 deletions test-d/camel-cased-properties.ts
@@ -1,15 +1,15 @@
import {expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {CamelCasedProperties} from '../index';

declare const foo: CamelCasedProperties<{A: number; B: {C: string}}>;

expectType<{a: number; b: {C: string}}>(foo);
expectTypeOf(foo).toEqualTypeOf<{a: number; b: {C: string}}>();

declare const bar: CamelCasedProperties<Array<{helloWorld: string}>>;
expectType<Array<{helloWorld: string}>>(bar);
expectTypeOf(bar).toEqualTypeOf<Array<{helloWorld: string}>>();

declare const fooBar: CamelCasedProperties<() => {a: string}>;
expectType<() => {a: string}>(fooBar);
expectTypeOf(fooBar).toEqualTypeOf<() => {a: string}>();

// Verify example
type User = {
Expand All @@ -21,4 +21,4 @@ const result: CamelCasedProperties<User> = {
userId: 1,
userName: 'Tom',
};
expectType<CamelCasedProperties<User>>(result);
expectTypeOf(result).toEqualTypeOf<CamelCasedProperties<User>>();
5 changes: 3 additions & 2 deletions test-d/class.ts
@@ -1,4 +1,3 @@
import {expectError} from 'tsd';
import type {Constructor} from '../index';

class Foo {
Expand All @@ -15,7 +14,9 @@ function fn(Cls: Constructor<Foo>): Foo {
}

function fn2(Cls: Constructor<Foo, [number, number]>): Foo {
expectError(new Cls(1, ''));
// @ts-expect-error
// eslint-disable-next-line no-new
new Cls(1, '');
return new Cls(1, 2);
}

Expand Down
8 changes: 4 additions & 4 deletions test-d/conditional-except.ts
@@ -1,4 +1,4 @@
import {expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {ConditionalExcept, Primitive} from '../index';

class Awesome {
Expand All @@ -19,10 +19,10 @@ type Example = {
};

declare const exampleConditionalExcept: ConditionalExcept<Example, string>;
expectType<{b?: string | number; c?: string; d: Record<string, unknown>}>(exampleConditionalExcept);
expectTypeOf(exampleConditionalExcept).toEqualTypeOf<{b?: string | number; c?: string; d: Record<string, unknown>}>();

declare const awesomeConditionalExcept: ConditionalExcept<Awesome, Primitive>;
expectType<{run: () => void}>(awesomeConditionalExcept);
expectTypeOf(awesomeConditionalExcept).toEqualTypeOf<{run: () => void}>();

declare const exampleConditionalExceptWithUndefined: ConditionalExcept<Example, string | undefined>;
expectType<{b?: string | number; d: Record<string, unknown>}>(exampleConditionalExceptWithUndefined);
expectTypeOf(exampleConditionalExceptWithUndefined).toEqualTypeOf<{b?: string | number; d: Record<string, unknown>}>();
6 changes: 3 additions & 3 deletions test-d/conditional-keys.ts
@@ -1,4 +1,4 @@
import {expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {ConditionalKeys} from '../index';

type Example = {
Expand All @@ -9,7 +9,7 @@ type Example = {
};

declare const exampleConditionalKeys: ConditionalKeys<Example, string>;
expectType<'a'>(exampleConditionalKeys);
expectTypeOf(exampleConditionalKeys).toEqualTypeOf<'a'>();

declare const exampleConditionalKeysWithUndefined: ConditionalKeys<Example, string | undefined>;
expectType<'a' | 'c'>(exampleConditionalKeysWithUndefined);
expectTypeOf(exampleConditionalKeysWithUndefined).toEqualTypeOf<'a' | 'c'>();
18 changes: 9 additions & 9 deletions test-d/conditional-pick-deep.ts
@@ -1,4 +1,4 @@
import {expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {ConditionalPickDeep} from '../index';

type Example = {
Expand All @@ -17,30 +17,30 @@ type Example = {
};

declare const stringPick: ConditionalPickDeep<Example, string>;
expectType<{a: string; c: {d: string}}>(stringPick);
expectTypeOf(stringPick).toEqualTypeOf<{a: string; c: {d: string}}>();

declare const stringPickOptional: ConditionalPickDeep<Example, string | undefined>;
expectType<{a: string; c: {d: string; e: {f?: string}}}>(stringPickOptional);
expectTypeOf(stringPickOptional).toEqualTypeOf<{a: string; c: {d: string; e: {f?: string}}}>();

declare const stringPickOptionalOnly: ConditionalPickDeep<Example, string | undefined, {condition: 'equality'}>;
expectType<{c: {e: {f?: string}}}>(stringPickOptionalOnly);
expectTypeOf(stringPickOptionalOnly).toEqualTypeOf<{c: {e: {f?: string}}}>();

declare const booleanPick: ConditionalPickDeep<Example, boolean | undefined>;
expectType<{c: {e: {g?: boolean}; j: boolean}}>(booleanPick);
expectTypeOf(booleanPick).toEqualTypeOf<{c: {e: {g?: boolean}; j: boolean}}>();

declare const numberPick: ConditionalPickDeep<Example, number>;
expectType<{}>(numberPick);
expectTypeOf(numberPick).toEqualTypeOf<{}>();

declare const stringOrBooleanPick: ConditionalPickDeep<Example, string | boolean>;
expectType<{
expectTypeOf(stringOrBooleanPick).toEqualTypeOf<{
a: string;
b: string | boolean;
c: {
d: string;
e: {h: string | boolean};
j: boolean;
};
}>(stringOrBooleanPick);
}>();

declare const stringOrBooleanPickOnly: ConditionalPickDeep<Example, string | boolean, {condition: 'equality'}>;
expectType<{b: string | boolean; c: {e: {h: string | boolean}}}>(stringOrBooleanPickOnly);
expectTypeOf(stringOrBooleanPickOnly).toEqualTypeOf<{b: string | boolean; c: {e: {h: string | boolean}}}>();
8 changes: 4 additions & 4 deletions test-d/conditional-pick.ts
@@ -1,4 +1,4 @@
import {expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {ConditionalPick, Primitive} from '../index';

class Awesome {
Expand All @@ -19,10 +19,10 @@ type Example = {
};

declare const exampleConditionalPick: ConditionalPick<Example, string>;
expectType< {a: string}>(exampleConditionalPick);
expectTypeOf(exampleConditionalPick).toEqualTypeOf< {a: string}>();

declare const awesomeConditionalPick: ConditionalPick<Awesome, Primitive>;
expectType<{name: string; successes: number; failures: bigint}>(awesomeConditionalPick);
expectTypeOf(awesomeConditionalPick).toEqualTypeOf<{name: string; successes: number; failures: bigint}>();

declare const exampleConditionalPickWithUndefined: ConditionalPick<Example, string | undefined>;
expectType<{a: string; c?: string}>(exampleConditionalPickWithUndefined);
expectTypeOf(exampleConditionalPickWithUndefined).toEqualTypeOf<{a: string; c?: string}>();
20 changes: 10 additions & 10 deletions test-d/conditional-simplify.ts
@@ -1,4 +1,4 @@
import {expectNotAssignable, expectType} from 'tsd';
import {expectTypeOf} from 'expect-type';
import type {ConditionalSimplify, ConditionalSimplifyDeep} from '../source/conditional-simplify';

type Position = {top: number; left: number};
Expand All @@ -11,7 +11,7 @@ type PositionAndSizeSimplified = ConditionalSimplify<PositionAndSizeIntersection
const position = {top: 120, left: 240};
const size = {width: 480, height: 600};
const positionAndSize = {...position, ...size};
expectType<PositionAndSizeSimplified>(positionAndSize);
expectTypeOf(positionAndSize).toEqualTypeOf<PositionAndSizeSimplified>();

// Exclude function type to be simplified.
type SomeFunction = (type: string) => string;
Expand All @@ -21,8 +21,8 @@ type SimplifiedFunctionPass = ConditionalSimplify<SomeFunction, Function>; // Re
declare const simplifiedFunctionFail: SimplifiedFunctionFail;
declare const simplifiedFunctionPass: SimplifiedFunctionPass;

expectNotAssignable<SomeFunction>(simplifiedFunctionFail);
expectType<SomeFunction>(simplifiedFunctionPass);
expectTypeOf(simplifiedFunctionFail).not.toMatchTypeOf<SomeFunction>();
expectTypeOf(simplifiedFunctionPass).toEqualTypeOf<SomeFunction>();

// Should simplify interface deeply.
type SomeNode = {
Expand All @@ -34,7 +34,7 @@ type SomeNode = {
type SomeNodeSimplified = ConditionalSimplifyDeep<SomeNode>;

const someNode = {parent: positionAndSize, childs: [{parent: positionAndSize}, {parent: positionAndSize}]};
expectType<SomeNodeSimplified>(someNode);
expectTypeOf(someNode).toEqualTypeOf<SomeNodeSimplified>();

// Should simplify interface deeply excluding Function type.
// TODO: Convert this to a `type`.
Expand All @@ -55,8 +55,8 @@ type MovableNodeSimplifiedPass = ConditionalSimplifyDeep<MovableCollection, Func
declare const movableNodeSimplifiedFail: MovableNodeSimplifiedFail;
declare const movableNodeSimplifiedPass: MovableNodeSimplifiedPass;

expectNotAssignable<MovableCollection>(movableNodeSimplifiedFail);
expectType<MovableCollection>(movableNodeSimplifiedPass);
expectTypeOf(movableNodeSimplifiedFail).not.toMatchTypeOf<MovableCollection>();
expectTypeOf(movableNodeSimplifiedPass).toEqualTypeOf<MovableCollection>();

const movablePosition = {
top: 42,
Expand All @@ -72,12 +72,12 @@ const movableNode = {
left: {position: movablePosition, size},
};

expectType<MovableNodeSimplifiedPass>(movableNode);
expectTypeOf(movableNode).toEqualTypeOf<MovableNodeSimplifiedPass>();

// Should exclude `Function` and `Size` type (mainly visual, mouse over the statement).
type ExcludeFunctionAndSize1 = ConditionalSimplifyDeep<MovableCollection, Function | Size>;
expectType<ExcludeFunctionAndSize1>(movableNode);
expectTypeOf(movableNode).toEqualTypeOf<ExcludeFunctionAndSize1>();

// Same as above but using `IncludeType` parameter (mainly visual, mouse over the statement).
type ExcludeFunctionAndSize2 = ConditionalSimplifyDeep<MovableCollection, Function, MovableCollection | Position>;
expectType<ExcludeFunctionAndSize2>(movableNode);
expectTypeOf(movableNode).toEqualTypeOf<ExcludeFunctionAndSize2>();