Created
December 9, 2022 21:03
-
-
Save Callek/0c5f8da2de7d892fa93afcbe4dfe3bfe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[callek@lyra type-fest]$ rg -i -C6 Error | |
readme.md | |
160- | |
161- submitContactForm({ | |
162- email: 'ex@mple.com', | |
163- message: 'Hi! Could you tell me more about…', | |
164- }); | |
165- | |
166: // TypeScript error: missing property 'message' | |
167- submitContactForm({ | |
168- email: 'ex@mple.com', | |
169- }); | |
170- ``` | |
171- </details> | |
172- | |
-- | |
179- [Playground](https://typescript-play.js.org/?target=6#code/AQ4UwOwVwW2AZA9gc3mAbmANsA3gKFCOAHkAzMgGkOJABEwAjKZa2kAUQCcvEu32AMQCGAF2FYBIAL4BufDRABLCKLBcywgMZgEKZOoDCiCGSXI8i4hGEwwALmABnUVxXJ57YFgzZHSVF8sT1BpBSItLGEnJz1kAy5LLy0TM2RHACUwYQATEywATwAeAITjU3MAPnkrCJMXLigtUT4AClxgGztKbyDgaX99I1TzAEokr1BRAAslJwA6FIqLAF48TtswHp9MHDla9hJGACswZvmyLjAwAC8wVpm5xZHkUZDaMKIwqyWXYCW0oN4sNlsA1h0ug5gAByACyBQAggAHJHQ7ZBIFoXbzBjMCz7OoQP5YIaJNYQMAAdziCVaALGNSIAHomcAACoFJFgADKWjcSNEwG4vC4ji0wggEEQguiTnMEGALWAV1yAFp8gVgEjeFyuKICvMrCTgVxnst5jtsGC4ljsPNhXxGaAWcAAOq6YRXYDCRg+RWIcA5JSC+kWdCepQ+v3RYCU3RInzRMCGwlpC19NYBW1Ye08R1AA) | |
180- | |
181- ```ts | |
182- enum LogLevel { | |
183- Off, | |
184- Debug, | |
185: Error, | |
186- Fatal | |
187- }; | |
188- | |
189- interface LoggerConfig { | |
190- name: string; | |
191- level: LogLevel; | |
-- | |
204- name: 'MyApp', | |
205- level: LogLevel.Debug | |
206- }; | |
207- | |
208- const logger = new Logger(config); | |
209- | |
210: // TypeScript Error: cannot assign to read-only property. | |
211: logger.config.level = LogLevel.Error; | |
212- | |
213- // We are able to edit config variable as we please. | |
214: config.level = LogLevel.Error; | |
215- ``` | |
216- </details> | |
217- | |
218-- [`Pick<T, K>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1422-L1427) - From `T`, pick a set of properties whose keys are in the union `K`. | |
219- <details> | |
220- <summary> | |
-- | |
287- firstName: 'John', | |
288- lastName: 'Doe', | |
289- yearsOfExperience: 0 | |
290- }); | |
291- | |
292- // `Record` forces you to initialize all of the property keys. | |
293: // TypeScript Error: "tech-lead" property is missing | |
294- const teamEmpty: Record<MemberPosition, null> = { | |
295- intern: null, | |
296- developer: null, | |
297- }; | |
298- ``` | |
299- </details> | |
-- | |
406- | |
407- serverBuilder | |
408- .port('8000') // portNumber = '8000' | |
409- .port(null) // portNumber = 8000 | |
410- .port(3000); // portNumber = 3000 | |
411- | |
412: // TypeScript error | |
413- serverBuilder.portNumber = null; | |
414- ``` | |
415- </details> | |
416- | |
417-- [`Parameters<T>`](https://github.com/Microsoft/TypeScript/blob/2961bc3fc0ea1117d4e53bc8e97fa76119bc33e3/src/lib/es5.d.ts#L1451-L1454) - Obtain the parameters of a function type in a tuple. | |
418- <details> | |
source/merge-exclusive.d.ts | |
26- | |
27-exclusiveOptions = {exclusive1: true}; | |
28-//=> Works | |
29-exclusiveOptions = {exclusive2: 'hi'}; | |
30-//=> Works | |
31-exclusiveOptions = {exclusive1: true, exclusive2: 'hi'}; | |
32://=> Error | |
33-``` | |
34-*/ | |
35-export type MergeExclusive<FirstType, SecondType> = | |
36- (FirstType | SecondType) extends object ? | |
37- (Without<FirstType, SecondType> & SecondType) | (Without<SecondType, FirstType> & FirstType) : | |
38- FirstType | SecondType; | |
source/readonly-deep.d.ts | |
23-export default data; | |
24- | |
25-// test.ts | |
26-import data from './main'; | |
27- | |
28-data.foo.push('bar'); | |
29://=> error TS2339: Property 'push' does not exist on type 'readonly string[]' | |
30-``` | |
31-*/ | |
32-export type ReadonlyDeep<T> = T extends Primitive | ((...arguments: any[]) => unknown) | |
33- ? T | |
34- : T extends ReadonlyMap<infer KeyType, infer ValueType> | |
35- ? ReadonlyMapDeep<KeyType, ValueType> | |
source/require-exactly-one.d.ts | |
19- text: () => string; | |
20- json: () => string; | |
21- secure: boolean; | |
22-}; | |
23- | |
24-const responder: RequireExactlyOne<Responder, 'text' | 'json'> = { | |
25: // Adding a `text` key here would cause a compile error. | |
26- | |
27- json: () => '{"message": "ok"}', | |
28- secure: true | |
29-}; | |
30-``` | |
31-*/ | |
license-cc0 | |
105- surrendered, licensed or otherwise affected by this document. | |
106- b. Affirmer offers the Work as-is and makes no representations or | |
107- warranties of any kind concerning the Work, express, implied, | |
108- statutory or otherwise, including without limitation warranties of | |
109- title, merchantability, fitness for a particular purpose, non | |
110- infringement, or the absence of latent or other defects, accuracy, or | |
111: the present or absence of errors, whether or not discoverable, all to | |
112- the greatest extent permissible under applicable law. | |
113- c. Affirmer disclaims responsibility for clearing rights of other persons | |
114- that may apply to the Work or any use thereof, including without | |
115- limitation any person's Copyright and Related Rights in the Work. | |
116- Further, Affirmer disclaims responsibility for obtaining any necessary | |
117- consents, permissions or other rights required for any use of the | |
test-d/require-at-least-one.ts | |
1:import {expectType, expectError} from 'tsd'; | |
2-import {RequireAtLeastOne} from '..'; | |
3- | |
4-type SystemMessages = { | |
5- default: string; | |
6- | |
7- macos?: string; | |
-- | |
15-const test = (_: ValidMessages): void => {}; | |
16- | |
17-test({macos: 'hey', default: 'hello'}); | |
18-test({linux: 'sup', default: 'hello', optional: 'howdy'}); | |
19-test({macos: 'hey', linux: 'sup', windows: 'hi', default: 'hello'}); | |
20- | |
21:expectError(test({})); | |
22:expectError(test({macos: 'hey'})); | |
23:expectError(test({default: 'hello'})); | |
24- | |
25-declare const atLeastOneWithoutKeys: RequireAtLeastOne<{a: number; b: number}>; | |
26-expectType<{a: number; b?: number} | {a?: number; b: number}>(atLeastOneWithoutKeys); | |
test-d/require-exactly-one.ts | |
1:import {expectType, expectError} from 'tsd'; | |
2-import {RequireExactlyOne} from '..'; | |
3- | |
4-type SystemMessages = { | |
5- default: string; | |
6- | |
7- macos: string; | |
-- | |
13-type ValidMessages = RequireExactlyOne<SystemMessages, 'macos' | 'linux'>; | |
14-const test = (_: ValidMessages): void => {}; | |
15- | |
16-test({macos: 'hey', default: 'hello'}); | |
17-test({linux: 'sup', optional: 'howdy', default: 'hello'}); | |
18- | |
19:expectError(test({})); | |
20:expectError(test({macos: 'hey', linux: 'sup', default: 'hello'})); | |
21- | |
22-declare const oneWithoutKeys: RequireExactlyOne<{a: number; b: number}>; | |
23-expectType<{a: number} | {b: number}>(oneWithoutKeys); | |
24:expectError(expectType<{a: number; b: number}>(oneWithoutKeys)); | |
test-d/merge-exclusive.ts | |
1:import {expectType, expectError} from 'tsd'; | |
2-import {MergeExclusive} from '..'; | |
3- | |
4-interface BaseOptions { | |
5- option?: string; | |
6-} | |
7- | |
-- | |
22- exclusiveVariation1 | |
23-); | |
24-expectType<{option?: string; exclusive1?: string; exclusive2: number}>( | |
25- exclusiveVariation2 | |
26-); | |
27- | |
28:expectError<Options>({exclusive1: true, exclusive2: 1}); | |
test-d/partial-deep.ts | |
1:import {expectType, expectError} from 'tsd'; | |
2-import {PartialDeep} from '..'; | |
3- | |
4-const foo = { | |
5- baz: 'fred', | |
6- bar: { | |
7- function: (_: string): void => {}, | |
-- | |
22- readonlyTuple: ['foo'] as const | |
23- } | |
24-}; | |
25- | |
26-let partialDeepFoo: PartialDeep<typeof foo> = foo; | |
27- | |
28:expectError(expectType<Partial<typeof foo>>(partialDeepFoo)); | |
29-const partialDeepBar: PartialDeep<typeof foo.bar> = foo.bar; | |
30-expectType<typeof partialDeepBar | undefined>(partialDeepFoo.bar); | |
31-expectType<((_: string) => void) | undefined>(partialDeepFoo.bar!.function); | |
32-expectType<object | undefined>(partialDeepFoo.bar!.object); | |
33-expectType<string | undefined>(partialDeepFoo.bar!.string); | |
34-expectType<number | undefined>(partialDeepFoo.bar!.number); | |
test-d/set-optional.ts | |
1:import {expectType, expectError} from 'tsd'; | |
2-import {SetOptional} from '..'; | |
3- | |
4-// Update one required and one optional to optional. | |
5-declare const variation1: SetOptional<{a: number; b?: string; c: boolean}, 'b' | 'c'>; | |
6-expectType<{a: number; b?: string; c?: boolean}>(variation1); | |
7- | |
-- | |
12-// Three optional remain optional. | |
13-declare const variation3: SetOptional<{a?: number; b?: string; c?: boolean}, 'a' | 'b' | 'c'>; | |
14-expectType<{a?: number; b?: string; c?: boolean}>(variation3); | |
15- | |
16-// Fail if type changes even if optional is right. | |
17-declare const variation4: SetOptional<{a: number; b?: string; c: boolean}, 'b' | 'c'>; | |
18:expectError<{a: boolean; b?: string; c?: boolean}>(variation4); | |
test-d/set-required.ts | |
1:import {expectType, expectError} from 'tsd'; | |
2-import {SetRequired} from '..'; | |
3- | |
4-// Update one required and one optional to required. | |
5-declare const variation1: SetRequired<{a?: number; b: string; c?: boolean}, 'b' | 'c'>; | |
6-expectType<{a?: number; b: string; c: boolean}>(variation1); | |
7- | |
-- | |
12-// Three required remain required. | |
13-declare const variation3: SetRequired<{a: number; b: string; c: boolean}, 'a' | 'b' | 'c'>; | |
14-expectType<{a: number; b: string; c: boolean}>(variation3); | |
15- | |
16-// Fail if type changes even if optional is right. | |
17-declare const variation4: SetRequired<{a?: number; b: string; c?: boolean}, 'b' | 'c'>; | |
18:expectError<{a?: boolean; b: string; c: boolean}>(variation4); | |
test-d/readonly-deep.ts | |
1:import {expectType, expectError} from 'tsd'; | |
2-import {ReadonlyDeep} from '../source/readonly-deep'; | |
3- | |
4-const data = { | |
5- object: { | |
6- foo: 'bar' | |
7- }, | |
-- | |
23-}; | |
24- | |
25-const readonlyData: ReadonlyDeep<typeof data> = data; | |
26- | |
27-readonlyData.fn('foo'); | |
28- | |
29:expectError(readonlyData.string = 'bar'); | |
30-expectType<{readonly foo: string}>(readonlyData.object); | |
31-expectType<string>(readonlyData.string); | |
32-expectType<number>(readonlyData.number); | |
33-expectType<boolean>(readonlyData.boolean); | |
34-expectType<symbol>(readonlyData.symbol); | |
35-expectType<null>(readonlyData.null); | |
test-d/class.ts | |
1:import {expectError} from 'tsd'; | |
2-import {Class} from '..'; | |
3- | |
4-class Foo { | |
5- constructor(x: number, y: any) { | |
6- console.log(x, y); | |
7- } | |
-- | |
12- | |
13-function fn(Cls: Class<Foo>): Foo { | |
14- return new Cls(1, '', 123); | |
15-} | |
16- | |
17-function fn2(Cls: Class<Foo, [number, number]>): Foo { | |
18: expectError(new Cls(1, '')); | |
19- return new Cls(1, 2); | |
20-} | |
21- | |
22-fn(Foo); | |
23-fn2(Foo); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment