@aryaemami59/tsconfig 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +1 -1
  2. package/package.json +75 -143
  3. package/scripts/build.ts +192 -182
  4. package/scripts/typeHelpers.ts +17 -11
  5. package/scripts/types.ts +302 -157
  6. package/src/bundler/commonjs/tsconfig.json +8 -0
  7. package/src/bundler/commonjs/with-js/tsconfig.json +9 -0
  8. package/src/bundler/esnext/tsconfig.json +1 -1
  9. package/src/bundler/preserve/tsconfig.json +1 -1
  10. package/src/create-react-app/tsconfig.json +2 -2
  11. package/src/node/commonjs/tsconfig.json +30 -0
  12. package/src/node/commonjs/with-js/tsconfig.json +9 -0
  13. package/src/node/{with-js → esnext/with-js}/tsconfig.json +1 -1
  14. package/src/node-10/commonjs/tsconfig.json +8 -0
  15. package/src/node-10/commonjs/with-js/tsconfig.json +9 -0
  16. package/src/node-10/{tsconfig.json → esnext/tsconfig.json} +1 -1
  17. package/src/node-10/{with-js → esnext/with-js}/tsconfig.json +1 -1
  18. package/src/node-16/{tsconfig.json → node16/tsconfig.json} +1 -1
  19. package/src/node-16/{with-js → node16/with-js}/tsconfig.json +1 -1
  20. package/src/node-16/node18/tsconfig.json +9 -0
  21. package/src/node-16/node18/with-js/tsconfig.json +9 -0
  22. package/src/node-16/node20/tsconfig.json +9 -0
  23. package/src/node-16/node20/with-js/tsconfig.json +9 -0
  24. package/src/node-next/node18/tsconfig.json +9 -0
  25. package/src/node-next/node18/with-js/tsconfig.json +9 -0
  26. package/src/node-next/node20/tsconfig.json +9 -0
  27. package/src/node-next/node20/with-js/tsconfig.json +9 -0
  28. package/src/node-next/{tsconfig.json → nodenext/tsconfig.json} +1 -1
  29. package/src/node-next/{with-js → nodenext/with-js}/tsconfig.json +1 -1
  30. /package/src/node/{tsconfig.json → esnext/tsconfig.json} +0 -0
package/scripts/build.ts CHANGED
@@ -2,259 +2,269 @@
2
2
 
3
3
  import * as fs from 'node:fs/promises'
4
4
  import * as path from 'node:path'
5
- import { format, resolveConfig } from 'prettier'
5
+ import type { Options } from 'prettier'
6
+ import { format } from 'prettier'
6
7
  import ts from 'typescript'
7
8
  import packageJson from '../package.json' with { type: 'json' }
8
- import type {
9
- ExcludeStrict,
10
- ExtractCapitalized,
11
- ExtractLowercase,
12
- ExtractStrict,
13
- KebabCase,
14
- Simplify,
15
- } from './typeHelpers.ts'
9
+ import type { ExcludeStrict, KebabCase, Simplify } from './typeHelpers.ts'
16
10
  import type { Module, ModuleResolution, TsConfigJson } from './types.ts'
17
11
 
18
12
  const { ModuleKind, ModuleResolutionKind } = ts.server.protocol
19
13
 
20
- type ModuleResolutionKindType = typeof ModuleResolutionKind
14
+ type ModuleResolutionKindType = Simplify<typeof ModuleResolutionKind>
21
15
 
22
- type ModuleKindType = typeof ModuleKind
16
+ type ModuleKindType = Simplify<typeof ModuleKind>
23
17
 
24
18
  const ROOT_DIRECTORY = path.join(import.meta.dirname, '..')
25
19
 
26
- type LowerCaseModuleResolutionKinds = ExcludeStrict<
27
- ExtractLowercase<ModuleResolution>,
28
- 'classic'
29
- >
30
-
31
20
  type CapitalizedModuleResolutionKinds = ExcludeStrict<
32
- ExtractCapitalized<ModuleResolution>,
21
+ ModuleResolution,
33
22
  'Classic'
34
23
  >
35
24
 
25
+ type LowerCaseModuleResolutionKinds =
26
+ Lowercase<CapitalizedModuleResolutionKinds>
27
+
36
28
  type CapitalizedModuleKinds = ExcludeStrict<
37
- ExtractCapitalized<Module>,
29
+ Module,
38
30
  'AMD' | 'None' | 'System' | 'UMD'
39
31
  >
40
32
 
41
- type LowerCaseModuleKinds = ExcludeStrict<
42
- ExtractLowercase<Module>,
43
- 'amd' | 'none' | 'system' | 'umd'
44
- >
33
+ type LowerCaseModuleKinds = Lowercase<CapitalizedModuleKinds>
45
34
 
46
35
  type CapitalizedToLowerCaseModuleResolutionKinds = {
47
- readonly [K in CapitalizedModuleResolutionKinds]: Lowercase<K>
36
+ readonly [PascalCasedModuleResolutionKind in CapitalizedModuleResolutionKinds]: Lowercase<PascalCasedModuleResolutionKind>
48
37
  }
49
38
 
50
39
  type LowerCaseToCapitalizedModuleResolutionKinds = {
51
- readonly [K in CapitalizedModuleResolutionKinds as Lowercase<K>]: K
40
+ readonly [PascalCasedModuleResolutionKind in CapitalizedModuleResolutionKinds as CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind]]: PascalCasedModuleResolutionKind
52
41
  }
53
42
 
54
43
  type PossibleModuleKinds = Simplify<{
55
- readonly [K in CapitalizedModuleResolutionKinds]: {
56
- readonly module: Lowercase<K> extends 'bundler'
57
- ? readonly ['esnext', 'preserve']
58
- : Lowercase<K> extends 'node' | 'node10'
59
- ? readonly ['esnext']
60
- : Lowercase<K> extends 'node16'
61
- ? readonly ['node16']
62
- : Lowercase<K> extends 'nodenext'
63
- ? readonly ['nodenext']
64
- : readonly ['esnext']
65
- readonly moduleResolution: Lowercase<K>
66
- }
44
+ readonly [PascalCasedModuleResolutionKind in CapitalizedModuleResolutionKinds]: Simplify<
45
+ Readonly<
46
+ Record<
47
+ 'modules',
48
+ CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind] extends 'bundler'
49
+ ? readonly ['commonjs', 'esnext', 'preserve']
50
+ : CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind] extends
51
+ | 'node'
52
+ | 'node10'
53
+ ? readonly ['commonjs', 'esnext']
54
+ : CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind] extends
55
+ | 'node16'
56
+ | 'nodenext'
57
+ ? readonly [
58
+ CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind],
59
+ 'node18',
60
+ 'node20',
61
+ ]
62
+ : readonly [
63
+ CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind],
64
+ ]
65
+ >
66
+ > & {
67
+ readonly directory: KebabCase<PascalCasedModuleResolutionKind>
68
+ readonly moduleResolution: CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind]
69
+ }
70
+ >
67
71
  }>
68
72
 
69
73
  type BaseConfigs = {
70
- readonly [K in CapitalizedModuleResolutionKinds as Lowercase<K>]: Simplify<{
71
- readonly directory: KebabCase<K>
72
- readonly module: PossibleModuleKinds[K]['module'][0]
73
- readonly moduleResolution: Lowercase<K>
74
- readonly subDirectory: [1] extends [
75
- PossibleModuleKinds[K]['module']['length'],
76
- ]
77
- ? ''
78
- : PossibleModuleKinds[K]['module'][0]
74
+ readonly [PascalCasedModuleResolutionKind in CapitalizedModuleResolutionKinds as CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind]]: Simplify<{
75
+ readonly directory: PossibleModuleKinds[PascalCasedModuleResolutionKind]['directory']
76
+ readonly moduleResolution: PossibleModuleKinds[PascalCasedModuleResolutionKind]['moduleResolution']
77
+ readonly modules: PossibleModuleKinds[PascalCasedModuleResolutionKind]['modules']
78
+ // readonly subDirectories: PossibleModuleKinds[PascalCasedModuleResolutionKind]['subDirectories']
79
79
  }>
80
80
  }
81
81
 
82
82
  const baseConfigs = {
83
83
  bundler: {
84
84
  directory: 'bundler',
85
- module: 'esnext',
86
85
  moduleResolution: 'bundler',
87
- subDirectory: 'esnext',
86
+ modules: ['commonjs', 'esnext', 'preserve'] as const,
87
+ // subDirectories: ['commonjs', 'esnext', 'preserve'] as const,
88
88
  },
89
89
  node: {
90
90
  directory: 'node',
91
- module: 'esnext',
92
91
  moduleResolution: 'node',
93
- subDirectory: '',
92
+ modules: ['commonjs', 'esnext'] as const,
93
+ // subDirectories: ['commonjs', 'esnext'] as const,
94
94
  },
95
95
  node10: {
96
96
  directory: 'node-10',
97
- module: 'esnext',
98
97
  moduleResolution: 'node10',
99
- subDirectory: '',
98
+ modules: ['commonjs', 'esnext'] as const,
99
+ // subDirectories: ['commonjs', 'esnext'] as const,
100
100
  },
101
101
  node16: {
102
102
  directory: 'node-16',
103
- module: 'node16',
104
103
  moduleResolution: 'node16',
105
- subDirectory: '',
104
+ modules: ['node16', 'node18', 'node20'] as const,
105
+ // subDirectories: ['node16'] as const,
106
106
  },
107
107
  nodenext: {
108
108
  directory: 'node-next',
109
- module: 'nodenext',
110
109
  moduleResolution: 'nodenext',
111
- subDirectory: '',
110
+ modules: ['nodenext', 'node18', 'node20'] as const,
111
+ // subDirectories: ['nodenext'] as const,
112
112
  },
113
113
  } as const satisfies BaseConfigs
114
114
 
115
- type AdditionalConfigs = {
116
- readonly [K in keyof PossibleModuleKinds as [1] extends [
117
- PossibleModuleKinds[K]['module']['length'],
118
- ]
119
- ? never
120
- : [undefined] extends [PossibleModuleKinds[K]['module']['1']]
121
- ? never
122
- : Lowercase<K>]: {
123
- readonly directory: KebabCase<K>
124
- readonly moduleResolution: PossibleModuleKinds[K]['moduleResolution']
125
- } & {
126
- [P in PossibleModuleKinds[K]['module'][ExtractStrict<
127
- keyof PossibleModuleKinds[K]['module'],
128
- number
129
- >]]: {
130
- readonly module: P
131
- readonly subDirectory: P
132
- }
133
- }[ExcludeStrict<
134
- PossibleModuleKinds[K]['module'][ExtractStrict<
135
- keyof PossibleModuleKinds[K]['module'],
136
- number
137
- >],
138
- PossibleModuleKinds[K]['module'][0]
139
- >]
140
- }
115
+ // type AdditionalConfigs = Simplify<{
116
+ // readonly [K in keyof PossibleModuleKinds as [1] extends [
117
+ // PossibleModuleKinds[K]['module']['length'],
118
+ // ]
119
+ // ? never
120
+ // : [undefined] extends [PossibleModuleKinds[K]['module']['1']]
121
+ // ? never
122
+ // : Lowercase<K>]: Simplify<
123
+ // {
124
+ // readonly directory: KebabCase<K>
125
+ // readonly moduleResolution: PossibleModuleKinds[K]['moduleResolution']
126
+ // } & {
127
+ // [P in PossibleModuleKinds[K]['module'][ExtractStrict<
128
+ // keyof PossibleModuleKinds[K]['module'],
129
+ // number
130
+ // >]]: {
131
+ // readonly module: P
132
+ // readonly subDirectory: P
133
+ // }
134
+ // }[ExcludeStrict<
135
+ // PossibleModuleKinds[K]['module'][ExtractStrict<
136
+ // keyof PossibleModuleKinds[K]['module'],
137
+ // number
138
+ // >],
139
+ // PossibleModuleKinds[K]['module'][0]
140
+ // >]
141
+ // >
142
+ // }>
141
143
 
142
- const additionalConfigs = {
143
- bundler: {
144
- directory: 'bundler',
145
- module: 'preserve',
146
- moduleResolution: 'bundler',
147
- subDirectory: 'preserve',
148
- },
149
- } as const satisfies AdditionalConfigs
144
+ // const additionalConfigs = {
145
+ // bundler: {
146
+ // directory: 'bundler',
147
+ // module: 'preserve',
148
+ // moduleResolution: 'bundler',
149
+ // subDirectory: 'preserve',
150
+ // },
151
+ // } as const satisfies AdditionalConfigs
150
152
 
151
153
  const build = async () => {
152
154
  await Promise.all(
153
- [...Object.entries(baseConfigs), ...Object.entries(additionalConfigs)].map(
154
- async ([
155
- ,
156
- { directory, module: moduleKind, moduleResolution, subDirectory },
157
- ]) => {
158
- const directoryPath = path.join(
159
- ROOT_DIRECTORY,
160
- 'src',
161
- directory,
162
- subDirectory,
163
- )
155
+ Object.entries(baseConfigs).map(
156
+ async ([, { directory, moduleResolution, modules }]) => {
157
+ await Promise.all(
158
+ modules.map(async (moduleKind) => {
159
+ const directoryPath = path.join(
160
+ ROOT_DIRECTORY,
161
+ 'src',
162
+ directory,
163
+ moduleKind,
164
+ )
164
165
 
165
- const tsconfigJsonPath = path.join(directoryPath, 'tsconfig.json')
166
+ const tsconfigJsonPath = path.join(directoryPath, 'tsconfig.json')
166
167
 
167
- const withJsDirectoryPath = path.join(directoryPath, 'with-js')
168
+ const withJsDirectoryPath = path.join(directoryPath, 'with-js')
168
169
 
169
- const withJsTsConfigJsonPath = path.join(
170
- withJsDirectoryPath,
171
- 'tsconfig.json',
172
- )
170
+ const withJsTsConfigJsonPath = path.join(
171
+ withJsDirectoryPath,
172
+ 'tsconfig.json',
173
+ )
173
174
 
174
- await fs.mkdir(directoryPath, {
175
- recursive: true,
176
- })
175
+ await fs.mkdir(directoryPath, {
176
+ recursive: true,
177
+ })
177
178
 
178
- await fs.mkdir(withJsDirectoryPath, {
179
- recursive: true,
180
- })
179
+ await fs.mkdir(withJsDirectoryPath, {
180
+ recursive: true,
181
+ })
181
182
 
182
- const baseTsconfigJson = {
183
- $schema: 'https://json.schemastore.org/tsconfig',
184
- compilerOptions: {},
185
- display: `TypeScript configuration with \`${moduleResolution}\` module resolution`,
186
- } as const satisfies TsConfigJson
183
+ const baseTsconfigJson = {
184
+ $schema: 'https://json.schemastore.org/tsconfig',
185
+ compilerOptions: {},
186
+ display: `TypeScript configuration with \`${moduleResolution}\` module resolution`,
187
+ } as const satisfies TsConfigJson
187
188
 
188
- const withJsTsConfigJson = {
189
- ...baseTsconfigJson,
190
- compilerOptions: {
191
- allowJs: true,
192
- checkJs: true,
193
- },
194
- display: `TypeScript configuration with module set to \`${moduleKind}\`, module resolution set to \`${moduleResolution}\`, and JavaScript files support enabled`,
195
- extends: [packageJson.name, directory, subDirectory]
196
- .filter((e) => !!e)
197
- .join('/'),
198
- } as const satisfies TsConfigJson
189
+ const withJsTsConfigJson = {
190
+ ...baseTsconfigJson,
191
+ compilerOptions: {
192
+ allowJs: true,
193
+ checkJs: true,
194
+ },
195
+ display: `TypeScript configuration with module set to \`${moduleKind}\`, module resolution set to \`${moduleResolution}\`, and JavaScript files support enabled`,
196
+ extends: [packageJson.name, moduleResolution, moduleKind]
197
+ .filter((e) => !!e)
198
+ .join('/'),
199
+ } as const satisfies TsConfigJson
199
200
 
200
- const tsconfigJson = {
201
- ...baseTsconfigJson,
202
- compilerOptions: {
203
- ...(moduleKind !== baseConfigs.node.module && {
204
- module: moduleKind,
205
- }),
206
- ...(moduleResolution !== 'node' && { moduleResolution }),
207
- ...(moduleResolution === 'node' && {
208
- allowSyntheticDefaultImports: true,
209
- declaration: true,
210
- esModuleInterop: true,
211
- forceConsistentCasingInFileNames: true,
212
- isolatedModules: true,
213
- jsx: 'react',
214
- lib: ['DOM', 'ESNext'],
215
- module: 'esnext',
216
- moduleDetection: 'force',
217
- moduleResolution,
218
- noEmit: false,
219
- noEmitOnError: true,
220
- noErrorTruncation: true,
221
- noFallthroughCasesInSwitch: true,
222
- noImplicitOverride: true,
223
- noImplicitReturns: true,
224
- resolveJsonModule: true,
225
- skipLibCheck: true,
226
- sourceMap: true,
227
- strict: true,
228
- target: 'esnext',
229
- types: ['node'],
230
- useDefineForClassFields: true,
231
- useUnknownInCatchVariables: true,
232
- }),
233
- },
234
- display: `TypeScript configuration with module set to \`${moduleKind}\` and module resolution set to \`${moduleResolution}\`${moduleResolution === 'node' ? ', intended for TypeScript versions earlier than 5.0.' : moduleResolution === 'node10' ? '. It serves as a backwards compatible replacement for the deprecated `node` module resolution.' : ''}`,
235
- ...(moduleResolution !== 'node' && {
236
- extends: `${packageJson.name}/node`,
237
- }),
238
- } as const satisfies TsConfigJson
201
+ const tsconfigJson = {
202
+ ...baseTsconfigJson,
203
+ compilerOptions: {
204
+ ...(moduleKind !== baseConfigs.node.modules[0] &&
205
+ moduleKind !== baseConfigs.node.modules[1] && {
206
+ module: moduleKind,
207
+ }),
208
+ ...(moduleResolution !== 'node' && {
209
+ // module: moduleKind,
210
+ moduleResolution,
211
+ }),
212
+ ...(moduleResolution === 'node' && {
213
+ allowSyntheticDefaultImports: true,
214
+ declaration: true,
215
+ esModuleInterop: true,
216
+ forceConsistentCasingInFileNames: true,
217
+ isolatedModules: true,
218
+ jsx: 'react',
219
+ lib: ['DOM', 'ESNext'],
220
+ module: moduleKind,
221
+ moduleDetection: 'force',
222
+ moduleResolution,
223
+ noEmit: false,
224
+ noEmitOnError: true,
225
+ noErrorTruncation: true,
226
+ noFallthroughCasesInSwitch: true,
227
+ noImplicitOverride: true,
228
+ noImplicitReturns: true,
229
+ resolveJsonModule: true,
230
+ skipLibCheck: true,
231
+ sourceMap: true,
232
+ strict: true,
233
+ target: 'esnext',
234
+ types: ['node'],
235
+ useDefineForClassFields: true,
236
+ useUnknownInCatchVariables: true,
237
+ }),
238
+ },
239
+ display: `TypeScript configuration with module set to \`${moduleKind}\` and module resolution set to \`${moduleResolution}\`${moduleResolution === 'node' ? ', intended for TypeScript versions earlier than 5.0.' : moduleResolution === 'node10' ? '. It serves as a backwards compatible replacement for the deprecated `node` module resolution.' : ''}`,
240
+ ...(moduleResolution !== 'node' && {
241
+ extends: `${packageJson.name}/node/${moduleKind === 'commonjs' || moduleKind === 'esnext' ? moduleKind : 'esnext'}`,
242
+ }),
243
+ } as const satisfies TsConfigJson
239
244
 
240
- const prettierConfig = (await resolveConfig(tsconfigJsonPath)) ?? {}
245
+ const prettierConfig = {
246
+ semi: false,
247
+ singleQuote: true,
248
+ } as const satisfies Options
241
249
 
242
- fs.writeFile(
243
- tsconfigJsonPath,
244
- await format(JSON.stringify(tsconfigJson, null, 2), {
245
- ...prettierConfig,
246
- filepath: tsconfigJsonPath,
247
- }),
248
- { encoding: 'utf-8' },
249
- )
250
+ fs.writeFile(
251
+ tsconfigJsonPath,
252
+ await format(JSON.stringify(tsconfigJson, null, 2), {
253
+ ...prettierConfig,
254
+ filepath: tsconfigJsonPath,
255
+ }),
256
+ { encoding: 'utf-8' },
257
+ )
250
258
 
251
- fs.writeFile(
252
- withJsTsConfigJsonPath,
253
- await format(JSON.stringify(withJsTsConfigJson, null, 2), {
254
- ...prettierConfig,
255
- filepath: withJsTsConfigJsonPath,
259
+ fs.writeFile(
260
+ withJsTsConfigJsonPath,
261
+ await format(JSON.stringify(withJsTsConfigJson, null, 2), {
262
+ ...prettierConfig,
263
+ filepath: withJsTsConfigJsonPath,
264
+ }),
265
+ { encoding: 'utf-8' },
266
+ )
256
267
  }),
257
- { encoding: 'utf-8' },
258
268
  )
259
269
  },
260
270
  ),
@@ -59,6 +59,8 @@ export type AnyNonNullishValue = NonNullable<unknown>
59
59
  * <caption>Basic usage</caption>
60
60
  *
61
61
  * ```ts
62
+ * import type { Simplify } from "./typeHelpers.js";
63
+ *
62
64
  * interface SomeInterface {
63
65
  * bar?: string;
64
66
  * baz: number | undefined;
@@ -82,12 +84,12 @@ export type AnyNonNullishValue = NonNullable<unknown>
82
84
  *
83
85
  * function fn(object: Record<string, unknown>): void {
84
86
  * console.log(object);
85
- * };
87
+ * }
86
88
  *
87
89
  * fn(literal); // ✅ Good: literal object type is sealed
88
90
  * fn(someType); // ✅ Good: type is sealed
89
91
  * // @ts-expect-error
90
- * fn(someInterface); // ❌ Error: Index signature for type "string" is missing in type "someInterface". Because `interface` can be re-opened
92
+ * fn(someInterface); // ❌ Error: Index signature for type 'string' is missing in type 'SomeInterface'. Because `interface` can be re-opened
91
93
  * fn(someInterface as Simplify<SomeInterface>); // ✅ Good: transform an `interface` into a `type`
92
94
  * ```
93
95
  *
@@ -98,13 +100,11 @@ export type AnyNonNullishValue = NonNullable<unknown>
98
100
  * @since v0.0.6 of **`@aryaemami59/tsconfig`**
99
101
  * @internal
100
102
  */
101
- export type Simplify<BaseType> = BaseType extends BaseType
102
- ? BaseType extends UnknownFunction
103
- ? BaseType
104
- : AnyNonNullishValue & {
105
- [KeyType in keyof BaseType]: BaseType[KeyType]
106
- }
107
- : never
103
+ export type Simplify<BaseType> = BaseType extends (...args: never[]) => unknown
104
+ ? BaseType
105
+ : NonNullable<unknown> & {
106
+ [KeyType in keyof BaseType]: BaseType[KeyType]
107
+ }
108
108
 
109
109
  /**
110
110
  * Omits keys from a type, **distributing** the operation over a union.
@@ -122,6 +122,8 @@ export type Simplify<BaseType> = BaseType extends BaseType
122
122
  * <caption>Demonstrating `Omit` vs `DistributedOmit`</caption>
123
123
  *
124
124
  * ```ts
125
+ * import type { DistributedOmit } from "./typeHelpers.js";
126
+ *
125
127
  * type A = {
126
128
  * a: number;
127
129
  * discriminant: "A";
@@ -146,7 +148,7 @@ export type Simplify<BaseType> = BaseType extends BaseType
146
148
  *
147
149
  * // @ts-expect-error
148
150
  * omittedUnion.a;
149
- * // => ❌ Error: Property 'a' does not exist on type '{ discriminant: "A" | "B" }'
151
+ * // => ❌ Error: Property 'a' does not exist on type 'Omit<Union, "foo">'.
150
152
  * }
151
153
  *
152
154
  * const distributedOmittedUnion: DistributedOmit<Union, "foo"> = {
@@ -189,6 +191,8 @@ export type DistributedOmit<
189
191
  * <caption>Demonstrating `Pick` vs `DistributedPick`</caption>
190
192
  *
191
193
  * ```ts
194
+ * import type { DistributedPick } from "./typeHelpers.js";
195
+ *
192
196
  * type A = {
193
197
  * discriminant: "A";
194
198
  * extraneous: boolean;
@@ -264,7 +268,9 @@ export type DistributedOmit<
264
268
  export type DistributedPick<
265
269
  ObjectType,
266
270
  KeyType extends keyof ObjectType,
267
- > = ObjectType extends unknown ? Pick<ObjectType, KeyType> : never
271
+ > = ObjectType extends unknown
272
+ ? Pick<ObjectType, Extract<KeyType, keyof ObjectType>>
273
+ : never
268
274
 
269
275
  /**
270
276
  * A stricter version of