|
1 | 1 | import {expectType} from 'tsd';
|
2 |
| -import {expectTypeOf} from 'expect-type'; |
3 |
| -import type {RequiredDeep} from '../index.d.ts'; |
| 2 | +import type {RequiredDeep, Simplify} from '../index.d.ts'; |
| 3 | +import type {BuiltIns} from '../source/internal/type.d.ts'; |
4 | 4 |
|
5 |
| -type Foo = { |
6 |
| - baz?: string | undefined; |
7 |
| - bar?: { |
8 |
| - function?: ((...arguments_: any[]) => void) | undefined; |
9 |
| - functionFixedArity?: ((argument1: unknown, argument2: unknown) => void); |
10 |
| - functionWithOverload?: { |
11 |
| - (argument: number): string; |
12 |
| - (argument1: string, argument2: number): number; |
13 |
| - }; |
14 |
| - namespace?: { |
15 |
| - (argument: number): string; |
16 |
| - key: string | undefined; |
17 |
| - }; |
18 |
| - namespaceWithOverload: { |
19 |
| - (argument: number): string; |
20 |
| - (argument1: string, argument2: number): number; |
21 |
| - key: string | undefined; |
22 |
| - }; |
23 |
| - object?: {key?: 'value'} | undefined; |
24 |
| - string?: string | undefined; |
25 |
| - number?: number | undefined; |
26 |
| - boolean?: false | undefined; |
27 |
| - date?: Date | undefined; |
28 |
| - regexp?: RegExp | undefined; |
29 |
| - symbol?: Symbol | undefined; |
30 |
| - null?: null | undefined; |
31 |
| - undefined?: undefined; |
32 |
| - map?: Map<string | undefined, string | undefined>; |
33 |
| - set?: Set<string | undefined>; |
34 |
| - array?: Array<string | undefined>; |
35 |
| - tuple?: ['foo' | undefined] | undefined; |
36 |
| - readonlyMap?: ReadonlyMap<string | undefined, string | undefined>; |
37 |
| - readonlySet?: ReadonlySet<string | undefined>; |
38 |
| - readonlyArray?: ReadonlyArray<string | undefined>; |
39 |
| - readonlyTuple?: readonly ['foo' | undefined] | undefined; |
40 |
| - weakMap?: WeakMap<{key: string | undefined}, string | undefined>; |
41 |
| - weakSet?: WeakSet<{key: string | undefined}>; |
42 |
| - promise?: Promise<string | undefined>; |
43 |
| - }; |
44 |
| -}; |
| 5 | +expectType<RequiredDeep<{a?: number; b: string}>>({} as {a: number; b: string}); |
| 6 | +expectType<RequiredDeep<{a?: {b?: {c?: string}; d?: string}}>>({} as {a: {b: {c: string}; d: string}}); |
| 7 | +expectType<RequiredDeep<{readonly a?: number; readonly b: {c?: string}}>>({} as {readonly a: number; readonly b: {c: string}}); |
| 8 | +expectType<RequiredDeep<{a?: Array<{b?: number}>}>>({} as {a: Array<{b: number}>}); |
| 9 | +expectType<RequiredDeep<{a?: [{b?: string}, number]}>>({} as {a: [{b: string}, number]}); |
| 10 | +expectType<RequiredDeep<{a?: number | {readonly b?: string}}>>({} as {a: number | {readonly b: string}}); |
| 11 | +expectType<RequiredDeep<{a?: {b: number} | {c?: string}}>>({} as {a: {b: number} | {c: string}}); |
| 12 | +expectType<RequiredDeep<{a?: {readonly b?: BuiltIns}}>>({} as {a: {readonly b: BuiltIns}}); |
45 | 13 |
|
46 |
| -type FooRequired = { |
47 |
| - baz: string; |
48 |
| - bar: { |
49 |
| - function: (...arguments_: any[]) => void; |
50 |
| - functionFixedArity: (argument1: unknown, argument2: unknown) => void; |
51 |
| - functionWithOverload: { |
52 |
| - (argument: number): string; |
53 |
| - (argument1: string, argument2: number): number; |
54 |
| - }; |
55 |
| - namespace: { |
56 |
| - (argument: number): string; |
57 |
| - key: string; |
58 |
| - }; |
59 |
| - namespaceWithOverload: { |
60 |
| - (argument: number): string; |
61 |
| - (argument1: string, argument2: number): number; |
62 |
| - key: string; |
63 |
| - }; |
64 |
| - object: {key: 'value'}; |
65 |
| - string: string; |
66 |
| - number: number; |
67 |
| - boolean: false; |
68 |
| - date: Date; |
69 |
| - regexp: RegExp; |
70 |
| - symbol: Symbol; |
71 |
| - null: null; |
72 |
| - undefined: never; |
73 |
| - map: Map<string, string>; |
74 |
| - set: Set<string>; |
75 |
| - array: string[]; |
76 |
| - tuple: ['foo']; |
77 |
| - readonlyMap: ReadonlyMap<string, string>; |
78 |
| - readonlySet: ReadonlySet<string>; |
79 |
| - readonlyArray: readonly string[]; |
80 |
| - readonlyTuple: readonly ['foo']; |
81 |
| - weakMap: WeakMap<{key: string}, string>; |
82 |
| - weakSet: WeakSet<{key: string}>; |
83 |
| - promise: Promise<string>; |
84 |
| - }; |
85 |
| -}; |
| 14 | +// Unions |
| 15 | +expectType<RequiredDeep<{a?: number} | {b?: string}>>({} as {a: number} | {b: string}); |
| 16 | +expectType<RequiredDeep<{v?: {a?: number}} | {w?: {b?: string}}>>({} as {v: {a: number}} | {w: {b: string}}); |
| 17 | +expectType<RequiredDeep<Map<{a: {b?: {c: {d?: number}}}}, {e?: string}> | Set<{a: {b?: {c: {d?: number}}}}>>>( |
| 18 | + {} as Map<{a: {b: {c: {d: number}}}}, {e: string}> | Set<{a: {b: {c: {d: number}}}}>, |
| 19 | +); |
86 | 20 |
|
87 |
| -type FooBar = Exclude<Foo['bar'], undefined>; |
88 |
| -type FooRequiredBar = FooRequired['bar']; |
| 21 | +// Index signatures |
| 22 | +expectType<RequiredDeep<{[x: string]: {a?: string; b: {c?: number}}}>>({} as {[x: string]: {a: string; b: {c: number}}}); |
| 23 | +expectType<RequiredDeep<{[x: string]: {[x: number]: {c?: number}}}>>({} as {[x: string]: {[x: number]: {c: number}}}); |
89 | 24 |
|
90 |
| -// TODO: Fix this case: https://github.com/mmkal/expect-type/issues/34 |
91 |
| -// @ts-expect-error |
92 |
| -expectTypeOf<RequiredDeep<Foo>>().toEqualTypeOf<FooRequired>(); |
93 |
| -expectTypeOf<RequiredDeep<FooBar['function']>>().toEqualTypeOf<FooRequiredBar['function']>(); |
94 |
| -expectTypeOf<RequiredDeep<FooBar['functionFixedArity']>>().toEqualTypeOf<FooRequiredBar['functionFixedArity']>(); |
95 |
| -expectTypeOf<RequiredDeep<FooBar['object']>>().toEqualTypeOf<FooRequiredBar['object']>(); |
96 |
| -expectTypeOf<RequiredDeep<FooBar['string']>>().toEqualTypeOf<FooRequiredBar['string']>(); |
97 |
| -expectTypeOf<RequiredDeep<FooBar['number']>>().toEqualTypeOf<FooRequiredBar['number']>(); |
98 |
| -expectTypeOf<RequiredDeep<FooBar['boolean']>>().toEqualTypeOf<FooRequiredBar['boolean']>(); |
99 |
| -expectTypeOf<RequiredDeep<FooBar['date']>>().toEqualTypeOf<FooRequiredBar['date']>(); |
100 |
| -expectTypeOf<RequiredDeep<FooBar['regexp']>>().toEqualTypeOf<FooRequiredBar['regexp']>(); |
101 |
| -expectTypeOf<RequiredDeep<FooBar['map']>>().toEqualTypeOf<FooRequiredBar['map']>(); |
102 |
| -expectTypeOf<RequiredDeep<FooBar['set']>>().toEqualTypeOf<FooRequiredBar['set']>(); |
103 |
| -expectTypeOf<RequiredDeep<FooBar['array']>>().toEqualTypeOf<FooRequiredBar['array']>(); |
104 |
| -expectTypeOf<RequiredDeep<FooBar['tuple']>>().toEqualTypeOf<FooRequiredBar['tuple']>(); |
105 |
| -expectTypeOf<RequiredDeep<FooBar['readonlyMap']>>().toEqualTypeOf<FooRequiredBar['readonlyMap']>(); |
106 |
| -expectTypeOf<RequiredDeep<FooBar['readonlySet']>>().toEqualTypeOf<FooRequiredBar['readonlySet']>(); |
107 |
| -expectTypeOf<RequiredDeep<FooBar['readonlyArray']>>().toEqualTypeOf<FooRequiredBar['readonlyArray']>(); |
108 |
| -expectTypeOf<RequiredDeep<FooBar['readonlyTuple']>>().toEqualTypeOf<FooRequiredBar['readonlyTuple']>(); |
109 |
| -expectTypeOf<RequiredDeep<FooBar['weakMap']>>().toEqualTypeOf<FooRequiredBar['weakMap']>(); |
110 |
| -expectTypeOf<RequiredDeep<FooBar['weakSet']>>().toEqualTypeOf<FooRequiredBar['weakSet']>(); |
111 |
| -expectTypeOf<RequiredDeep<FooBar['promise']>>().toEqualTypeOf<FooRequiredBar['promise']>(); |
| 25 | +// Optional with `undefined` |
| 26 | +// This behaviour changes depending on `exactOptionalPropertyTypes` compiler option, refer https://github.com/sindresorhus/type-fest/issues/1217 |
| 27 | +expectType<RequiredDeep<{a?: number | undefined}>>({} as {a: number | undefined}); |
| 28 | +expectType<RequiredDeep<{a?: {b: number} | undefined}>>({} as {a: {b: number} | undefined}); |
| 29 | +expectType<RequiredDeep<{a?: undefined}>>({} as {a: undefined}); |
112 | 30 |
|
113 |
| -// TODO: Fix this case: https://github.com/mmkal/expect-type/issues/34 |
114 |
| -// @ts-expect-error |
115 |
| -expectTypeOf<RequiredDeep<FooBar['namespace']>>().toEqualTypeOf<FooRequiredBar['namespace']>(); |
| 31 | +// Tuples |
| 32 | +expectType<RequiredDeep<[string, number, boolean]>>({} as [string, number, boolean]); // All required |
| 33 | +expectType<RequiredDeep<readonly [string, number?, boolean?]>>({} as readonly [string, number, boolean]); // Required and optional |
| 34 | +expectType<RequiredDeep<[string?, number?, boolean?]>>({} as [string, number, boolean]); // All optional |
| 35 | +expectType<RequiredDeep<[string, number, ...boolean[]]>>({} as [string, number, ...boolean[]]); // Required and trailing rest |
| 36 | +expectType<RequiredDeep<readonly [string, number?, ...boolean[]]>>({} as readonly [string, number, ...boolean[]]); // Required, optional and trailing rest |
| 37 | +expectType<RequiredDeep<[string?, number?, ...boolean[]]>>({} as [string, number, ...boolean[]]); // Optional and trailing rest |
| 38 | +expectType<RequiredDeep<[...string[], number, boolean]>>({} as [...string[], number, boolean]); // Leading rest |
| 39 | +expectType<RequiredDeep<[number, ...string[], number, boolean]>>({} as [number, ...string[], number, boolean]); // Rest in middle |
| 40 | + |
| 41 | +// Nested tuples |
| 42 | +expectType<RequiredDeep<[[string, number?], [boolean, Date]?, [RegExp?, number?]?]>>({} as [[string, number], [boolean, Date], [RegExp, number]]); |
| 43 | +expectType<RequiredDeep<[[{a?: string}, {b: number; c?: string}?], ...Array<[boolean, boolean?]>]>>({} as [[{a: string}, {b: number; c: string}], ...Array<[boolean, boolean]>]); |
| 44 | + |
| 45 | +// Non-tuple arrays |
| 46 | +expectType<RequiredDeep<string[]>>({} as string[]); |
| 47 | +expectType<RequiredDeep<Array<string | undefined>>>({} as string[]); |
| 48 | +expectType<RequiredDeep<ReadonlyArray<string | undefined>>>({} as readonly string[]); |
| 49 | + |
| 50 | +// Maps |
| 51 | +expectType<RequiredDeep<Map<{a?: string; b?: number}, {a?: string; b?: number}>>>({} as Map<{a: string; b: number}, {a: string; b: number}>); |
| 52 | +expectType<RequiredDeep<ReadonlyMap<{a?: string; b?: number}, {a?: string; b?: number}>>>({} as ReadonlyMap<{a: string; b: number}, {a: string; b: number}>); |
| 53 | +expectType<RequiredDeep<WeakMap<{a?: string; b?: number}, {a?: string; b?: number}>>>({} as WeakMap<{a: string; b: number}, {a: string; b: number}>); |
116 | 54 |
|
117 |
| -expectTypeOf<RequiredDeep<FooBar['undefined']>>().toBeNever(); |
118 |
| -expectTypeOf<RequiredDeep<FooBar['null']>>().toEqualTypeOf<FooRequiredBar['null']>(); |
| 55 | +// Sets |
| 56 | +expectType<RequiredDeep<Set<{a?: string; b?: number}>>>({} as Set<{a: string; b: number}>); |
| 57 | +expectType<RequiredDeep<ReadonlySet<{a?: string; b?: number}>>>({} as ReadonlySet<{a: string; b: number}>); |
| 58 | +expectType<RequiredDeep<WeakSet<{a?: string; b?: number}>>>({} as WeakSet<{a: string; b: number}>); |
119 | 59 |
|
120 |
| -// These currently need to be left alone due to TypeScript limitations. |
121 |
| -// @see https://github.com/microsoft/TypeScript/issues/29732 |
122 |
| -expectType<string>(({} as unknown as RequiredDeep<FooBar['functionWithOverload']>)(0)); |
123 |
| -expectType<number>(({} as unknown as RequiredDeep<FooBar['functionWithOverload']>)('foo', 0)); |
124 |
| -expectType<string>(({} as unknown as RequiredDeep<FooBar['namespaceWithOverload']>)(0)); |
125 |
| -expectType<number>(({} as unknown as RequiredDeep<FooBar['namespaceWithOverload']>)('foo', 0)); |
| 60 | +// Functions |
| 61 | +type FunctionWithProperties = {(a1: string, a2: number): boolean; p1?: string; readonly p2?: number}; |
| 62 | +declare const functionWithProperties: RequiredDeep<FunctionWithProperties>; |
| 63 | +expectType<boolean>(functionWithProperties('foo', 1)); |
| 64 | +expectType<{p1: string; readonly p2: number}>({} as Simplify<typeof functionWithProperties>); // `Simplify` removes the call signature from `typeof functionWithProperties` |
| 65 | + |
| 66 | +type FunctionWithProperties2 = {(a1: boolean, ...a2: string[]): number; p1?: {p2?: string; p3: {readonly p4?: boolean}}}; |
| 67 | +declare const functionWithProperties2: RequiredDeep<FunctionWithProperties2>; |
| 68 | +expectType<number>(functionWithProperties2(true, 'foo', 'bar')); |
| 69 | +expectType<{p1: {p2: string; p3: {readonly p4: boolean}}}>({} as Simplify<typeof functionWithProperties2>); |
| 70 | + |
| 71 | +type FunctionWithProperties3 = {(): void; p1?: {p2?: string; p3: [{p4?: number}, string?]}}; |
| 72 | +declare const functionWithProperties3: RequiredDeep<FunctionWithProperties3>; |
| 73 | +expectType<void>(functionWithProperties3()); |
| 74 | +expectType<{p1: {p2: string; p3: [{p4: number}, string]}}>({} as Simplify<typeof functionWithProperties3>); |
| 75 | + |
| 76 | +// Properties with functions containing multiple call signatures are not made required due to a TS limitation, refer https://github.com/microsoft/TypeScript/issues/29732 |
| 77 | +type FunctionWithProperties4 = {(a1: number): string; (a1: string, a2: number): number; p1?: string}; |
| 78 | +declare const functionWithProperties4: RequiredDeep<FunctionWithProperties4>; |
| 79 | +// @ts-expect-error |
| 80 | +expectType<{p1: string}>({} as Simplify<typeof functionWithProperties4>); |
0 commit comments