@aryaemami59/tsconfig 0.0.7 → 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 +190 -184
  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
@@ -6,259 +6,265 @@ import type { Options } from 'prettier'
6
6
  import { format } from 'prettier'
7
7
  import ts from 'typescript'
8
8
  import packageJson from '../package.json' with { type: 'json' }
9
- import type {
10
- ExcludeStrict,
11
- ExtractCapitalized,
12
- ExtractLowercase,
13
- ExtractStrict,
14
- KebabCase,
15
- Simplify,
16
- } from './typeHelpers.ts'
9
+ import type { ExcludeStrict, KebabCase, Simplify } from './typeHelpers.ts'
17
10
  import type { Module, ModuleResolution, TsConfigJson } from './types.ts'
18
11
 
19
12
  const { ModuleKind, ModuleResolutionKind } = ts.server.protocol
20
13
 
21
- type ModuleResolutionKindType = typeof ModuleResolutionKind
14
+ type ModuleResolutionKindType = Simplify<typeof ModuleResolutionKind>
22
15
 
23
- type ModuleKindType = typeof ModuleKind
16
+ type ModuleKindType = Simplify<typeof ModuleKind>
24
17
 
25
18
  const ROOT_DIRECTORY = path.join(import.meta.dirname, '..')
26
19
 
27
- type LowerCaseModuleResolutionKinds = ExcludeStrict<
28
- ExtractLowercase<ModuleResolution>,
29
- 'classic'
30
- >
31
-
32
20
  type CapitalizedModuleResolutionKinds = ExcludeStrict<
33
- ExtractCapitalized<ModuleResolution>,
21
+ ModuleResolution,
34
22
  'Classic'
35
23
  >
36
24
 
25
+ type LowerCaseModuleResolutionKinds =
26
+ Lowercase<CapitalizedModuleResolutionKinds>
27
+
37
28
  type CapitalizedModuleKinds = ExcludeStrict<
38
- ExtractCapitalized<Module>,
29
+ Module,
39
30
  'AMD' | 'None' | 'System' | 'UMD'
40
31
  >
41
32
 
42
- type LowerCaseModuleKinds = ExcludeStrict<
43
- ExtractLowercase<Module>,
44
- 'amd' | 'none' | 'system' | 'umd'
45
- >
33
+ type LowerCaseModuleKinds = Lowercase<CapitalizedModuleKinds>
46
34
 
47
35
  type CapitalizedToLowerCaseModuleResolutionKinds = {
48
- readonly [K in CapitalizedModuleResolutionKinds]: Lowercase<K>
36
+ readonly [PascalCasedModuleResolutionKind in CapitalizedModuleResolutionKinds]: Lowercase<PascalCasedModuleResolutionKind>
49
37
  }
50
38
 
51
39
  type LowerCaseToCapitalizedModuleResolutionKinds = {
52
- readonly [K in CapitalizedModuleResolutionKinds as Lowercase<K>]: K
40
+ readonly [PascalCasedModuleResolutionKind in CapitalizedModuleResolutionKinds as CapitalizedToLowerCaseModuleResolutionKinds[PascalCasedModuleResolutionKind]]: PascalCasedModuleResolutionKind
53
41
  }
54
42
 
55
43
  type PossibleModuleKinds = Simplify<{
56
- readonly [K in CapitalizedModuleResolutionKinds]: {
57
- readonly module: Lowercase<K> extends 'bundler'
58
- ? readonly ['esnext', 'preserve']
59
- : Lowercase<K> extends 'node' | 'node10'
60
- ? readonly ['esnext']
61
- : Lowercase<K> extends 'node16'
62
- ? readonly ['node16']
63
- : Lowercase<K> extends 'nodenext'
64
- ? readonly ['nodenext']
65
- : readonly ['esnext']
66
- readonly moduleResolution: Lowercase<K>
67
- }
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
+ >
68
71
  }>
69
72
 
70
73
  type BaseConfigs = {
71
- readonly [K in CapitalizedModuleResolutionKinds as Lowercase<K>]: Simplify<{
72
- readonly directory: KebabCase<K>
73
- readonly module: PossibleModuleKinds[K]['module'][0]
74
- readonly moduleResolution: Lowercase<K>
75
- readonly subDirectory: [1] extends [
76
- PossibleModuleKinds[K]['module']['length'],
77
- ]
78
- ? ''
79
- : 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']
80
79
  }>
81
80
  }
82
81
 
83
82
  const baseConfigs = {
84
83
  bundler: {
85
84
  directory: 'bundler',
86
- module: 'esnext',
87
85
  moduleResolution: 'bundler',
88
- subDirectory: 'esnext',
86
+ modules: ['commonjs', 'esnext', 'preserve'] as const,
87
+ // subDirectories: ['commonjs', 'esnext', 'preserve'] as const,
89
88
  },
90
89
  node: {
91
90
  directory: 'node',
92
- module: 'esnext',
93
91
  moduleResolution: 'node',
94
- subDirectory: '',
92
+ modules: ['commonjs', 'esnext'] as const,
93
+ // subDirectories: ['commonjs', 'esnext'] as const,
95
94
  },
96
95
  node10: {
97
96
  directory: 'node-10',
98
- module: 'esnext',
99
97
  moduleResolution: 'node10',
100
- subDirectory: '',
98
+ modules: ['commonjs', 'esnext'] as const,
99
+ // subDirectories: ['commonjs', 'esnext'] as const,
101
100
  },
102
101
  node16: {
103
102
  directory: 'node-16',
104
- module: 'node16',
105
103
  moduleResolution: 'node16',
106
- subDirectory: '',
104
+ modules: ['node16', 'node18', 'node20'] as const,
105
+ // subDirectories: ['node16'] as const,
107
106
  },
108
107
  nodenext: {
109
108
  directory: 'node-next',
110
- module: 'nodenext',
111
109
  moduleResolution: 'nodenext',
112
- subDirectory: '',
110
+ modules: ['nodenext', 'node18', 'node20'] as const,
111
+ // subDirectories: ['nodenext'] as const,
113
112
  },
114
113
  } as const satisfies BaseConfigs
115
114
 
116
- type AdditionalConfigs = {
117
- readonly [K in keyof PossibleModuleKinds as [1] extends [
118
- PossibleModuleKinds[K]['module']['length'],
119
- ]
120
- ? never
121
- : [undefined] extends [PossibleModuleKinds[K]['module']['1']]
122
- ? never
123
- : Lowercase<K>]: {
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
- }
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
+ // }>
142
143
 
143
- const additionalConfigs = {
144
- bundler: {
145
- directory: 'bundler',
146
- module: 'preserve',
147
- moduleResolution: 'bundler',
148
- subDirectory: 'preserve',
149
- },
150
- } 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
151
152
 
152
153
  const build = async () => {
153
154
  await Promise.all(
154
- [...Object.entries(baseConfigs), ...Object.entries(additionalConfigs)].map(
155
- async ([
156
- ,
157
- { directory, module: moduleKind, moduleResolution, subDirectory },
158
- ]) => {
159
- const directoryPath = path.join(
160
- ROOT_DIRECTORY,
161
- 'src',
162
- directory,
163
- subDirectory,
164
- )
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
+ )
165
165
 
166
- const tsconfigJsonPath = path.join(directoryPath, 'tsconfig.json')
166
+ const tsconfigJsonPath = path.join(directoryPath, 'tsconfig.json')
167
167
 
168
- const withJsDirectoryPath = path.join(directoryPath, 'with-js')
168
+ const withJsDirectoryPath = path.join(directoryPath, 'with-js')
169
169
 
170
- const withJsTsConfigJsonPath = path.join(
171
- withJsDirectoryPath,
172
- 'tsconfig.json',
173
- )
170
+ const withJsTsConfigJsonPath = path.join(
171
+ withJsDirectoryPath,
172
+ 'tsconfig.json',
173
+ )
174
174
 
175
- await fs.mkdir(directoryPath, {
176
- recursive: true,
177
- })
175
+ await fs.mkdir(directoryPath, {
176
+ recursive: true,
177
+ })
178
178
 
179
- await fs.mkdir(withJsDirectoryPath, {
180
- recursive: true,
181
- })
179
+ await fs.mkdir(withJsDirectoryPath, {
180
+ recursive: true,
181
+ })
182
182
 
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
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
188
188
 
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, directory, subDirectory]
197
- .filter((e) => !!e)
198
- .join('/'),
199
- } 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
200
200
 
201
- const tsconfigJson = {
202
- ...baseTsconfigJson,
203
- compilerOptions: {
204
- ...(moduleKind !== baseConfigs.node.module && {
205
- module: moduleKind,
206
- }),
207
- ...(moduleResolution !== 'node' && { moduleResolution }),
208
- ...(moduleResolution === 'node' && {
209
- allowSyntheticDefaultImports: true,
210
- declaration: true,
211
- esModuleInterop: true,
212
- forceConsistentCasingInFileNames: true,
213
- isolatedModules: true,
214
- jsx: 'react',
215
- lib: ['DOM', 'ESNext'],
216
- module: 'esnext',
217
- moduleDetection: 'force',
218
- moduleResolution,
219
- noEmit: false,
220
- noEmitOnError: true,
221
- noErrorTruncation: true,
222
- noFallthroughCasesInSwitch: true,
223
- noImplicitOverride: true,
224
- noImplicitReturns: true,
225
- resolveJsonModule: true,
226
- skipLibCheck: true,
227
- sourceMap: true,
228
- strict: true,
229
- target: 'esnext',
230
- types: ['node'],
231
- useDefineForClassFields: true,
232
- useUnknownInCatchVariables: true,
233
- }),
234
- },
235
- 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.' : ''}`,
236
- ...(moduleResolution !== 'node' && {
237
- extends: `${packageJson.name}/node`,
238
- }),
239
- } 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
240
244
 
241
- const prettierConfig = {
242
- semi: false,
243
- singleQuote: true,
244
- } as const satisfies Options
245
+ const prettierConfig = {
246
+ semi: false,
247
+ singleQuote: true,
248
+ } as const satisfies Options
245
249
 
246
- fs.writeFile(
247
- tsconfigJsonPath,
248
- await format(JSON.stringify(tsconfigJson, null, 2), {
249
- ...prettierConfig,
250
- filepath: tsconfigJsonPath,
251
- }),
252
- { encoding: 'utf-8' },
253
- )
250
+ fs.writeFile(
251
+ tsconfigJsonPath,
252
+ await format(JSON.stringify(tsconfigJson, null, 2), {
253
+ ...prettierConfig,
254
+ filepath: tsconfigJsonPath,
255
+ }),
256
+ { encoding: 'utf-8' },
257
+ )
254
258
 
255
- fs.writeFile(
256
- withJsTsConfigJsonPath,
257
- await format(JSON.stringify(withJsTsConfigJson, null, 2), {
258
- ...prettierConfig,
259
- 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
+ )
260
267
  }),
261
- { encoding: 'utf-8' },
262
268
  )
263
269
  },
264
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