Skip to content

Commit e23f56b

Browse files
committed
chore: improve ternary types
chore: wip chore: wip chore: wip
1 parent e475fe6 commit e23f56b

File tree

5 files changed

+116
-37
lines changed

5 files changed

+116
-37
lines changed

fixtures/input/type.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,19 @@ export type DynamicRecord<K extends PropertyKey> = {
6565
? Record<string, unknown>
6666
: never
6767
}
68+
69+
export type RecordMerge<T, U> = IsEmptyType<U> extends true
70+
? T
71+
: [T, U] extends [any[], any[]]
72+
? U
73+
: [T, U] extends [object, object]
74+
? {
75+
[K in keyof T | keyof U]: K extends keyof T
76+
? K extends keyof U
77+
? RecordMerge<T[K], U[K]>
78+
: T[K]
79+
: K extends keyof U
80+
? U[K]
81+
: never
82+
}
83+
: U

fixtures/output/0003.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ declare interface AutoImportsPlugin {
99
export declare function autoImports(options: Partial<UnimportOptions & { dts: string }>): AutoImportsPlugin;
1010
export declare type AutoImportsOptions = UnimportOptions
1111

12-
export default autoImports;
12+
export default autoImports

fixtures/output/0004.d.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ export declare interface DtsGenerationConfig {
99
verbose: boolean
1010
}
1111
export declare type DtsGenerationOption = Partial<DtsGenerationConfig>
12-
export declare type DtsGenerationOptions = DtsGenerationOption | DtsGenerationOption[]
13-
export declare interface RegexPatterns {
12+
13+
export type DtsGenerationOptions = DtsGenerationOption | DtsGenerationOption[]
14+
15+
export interface RegexPatterns {
1416
readonly typeImport: RegExp
1517
readonly regularImport: RegExp
1618
readonly bracketOpen: RegExp
@@ -37,7 +39,8 @@ export declare interface RegexPatterns {
3739
readonly moduleDeclaration: RegExp
3840
readonly moduleAugmentation: RegExp
3941
}
40-
export declare interface ImportTrackingState {
42+
43+
export interface ImportTrackingState {
4144
typeImports: Map<string, Set<string>>
4245
valueImports: Map<string, Set<string>>
4346
usedTypes: Set<string>
@@ -49,7 +52,8 @@ export declare interface ImportTrackingState {
4952
typeExportSources: Map<string, string>
5053
defaultExportValue?: string
5154
}
52-
export declare interface ProcessingState {
55+
56+
export interface ProcessingState {
5357
dtsLines: string[]
5458
imports: string[]
5559
usedTypes: Set<string>
@@ -74,33 +78,38 @@ export declare interface ProcessingState {
7478
defaultExports: Set<string>
7579
currentScope: 'top' | 'function'
7680
}
77-
export declare interface MethodSignature {
81+
82+
export interface MethodSignature {
7883
name: string
7984
async: boolean
8085
generics: string
8186
params: string
8287
returnType: string
8388
}
84-
export declare interface PropertyInfo {
89+
90+
export interface PropertyInfo {
8591
key: string
8692
value: string
8793
type: string
8894
nested?: PropertyInfo[]
8995
method?: MethodSignature
9096
}
91-
export declare interface ImportInfo {
97+
98+
export interface ImportInfo {
9299
kind: 'type' | 'value' | 'mixed'
93100
usedTypes: Set<string>
94101
usedValues: Set<string>
95102
source: string
96103
}
97-
export declare interface FunctionSignature {
104+
105+
export interface FunctionSignature {
98106
name: string
99107
params: string
100108
returnType: string
101109
generics: string
102110
}
103-
export declare interface ProcessedMethod {
111+
112+
export interface ProcessedMethod {
104113
name: string
105114
signature: string
106115
}

fixtures/output/type.d.ts

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,43 +9,68 @@ export type ComplexUnionIntersection =
99
& {
1010
metadata: Record<string, unknown>
1111
}
12-
export declare type ReadonlyDeep<T> = {
12+
13+
14+
export type ReadonlyDeep<T> = {
1315
readonly [P in keyof T]: T[P] extends object ? ReadonlyDeep<T[P]> : T[P]
1416
}
15-
export declare type ConditionalResponse<T> = T extends Array<infer U>
17+
18+
export type ConditionalResponse<T> = T extends Array<infer U>
1619
? ApiResponse<U[]>
1720
: T extends object
1821
? ApiResponse<T>
1922
: ApiResponse<string>
20-
export declare type EventType = 'click' | 'focus' | 'blur'
23+
24+
export type EventType = 'click' | 'focus' | 'blur'
2125
export type ElementType = 'button' | 'input' | 'form'
22-
export declare type EventHandler = `on${Capitalize<EventType>}${Capitalize<ElementType>}`
26+
export type EventHandler = `on${Capitalize<EventType>}${Capitalize<ElementType>}`
2327

2428
export type RecursiveObject = {
2529
id: string
2630
children?: RecursiveObject[]
2731
parent?: RecursiveObject
2832
metadata: Record<string, unknown>
2933
}
30-
export declare type UserId = string & { readonly __brand: unique symbol }
34+
35+
export type UserId = string & { readonly __brand: unique symbol }
3136
export type ProductId = number & {
3237
readonly __brand: unique symbol
3338
}
34-
export declare type DeepPartial<T> = T extends object ? {
39+
40+
export type DeepPartial<T> = T extends object ? {
3541
[P in keyof T]?: DeepPartial<T[P]>
3642
} : T
37-
export declare type DeepRequired<T> = T extends object ? {
43+
44+
export type DeepRequired<T> = T extends object ? {
3845
[P in keyof T]-?: DeepRequired<T[P]>
3946
} : T
40-
export declare type PolymorphicComponent<P = {}> = {
47+
48+
export type PolymorphicComponent<P = {}> = {
4149
<C extends React.ElementType>(
4250
props: { as?: C } & Omit<React.ComponentPropsWithRef<C>, keyof P> & P
4351
): React.ReactElement | null
4452
}
45-
export declare type DynamicRecord<K extends PropertyKey> = {
53+
54+
export type DynamicRecord<K extends PropertyKey> = {
4655
[P in K]: P extends number
4756
? Array<unknown>
4857
: P extends string
4958
? Record<string, unknown>
5059
: never
51-
}
60+
}
61+
62+
export type RecordMerge<T, U> = IsEmptyType<U> extends true
63+
? T
64+
: [T, U] extends [any[], any[]]
65+
? U
66+
: [T, U] extends [object, object]
67+
? {
68+
[K in keyof T | keyof U]: K extends keyof T
69+
? K extends keyof U
70+
? RecordMerge<T[K], U[K]>
71+
: T[K]
72+
: K extends keyof U
73+
? U[K]
74+
: never
75+
}
76+
: U

src/extract.ts

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,7 +1142,6 @@ function isDeclarationStart(line: string): boolean {
11421142
|| trimmed.startsWith('function ')
11431143
|| trimmed.startsWith('async function ')
11441144
|| trimmed.startsWith('declare ')
1145-
|| trimmed.startsWith('declare module')
11461145
|| /^export\s+(?:interface|type|const|function\*?|async\s+function\*?)/.test(trimmed)
11471146
)
11481147
}
@@ -1925,22 +1924,52 @@ function processSourceFile(content: string, state: ProcessingState): void {
19251924
bracketDepth += openCurly - closeCurly
19261925
angleDepth += openAngle - closeAngle
19271926

1928-
// Check for end of declaration
1929-
const isComplete = bracketDepth === 0 && angleDepth === 0 && trimmedLine.endsWith('}')
1930-
1931-
// Look ahead for continuation
1932-
const nextLine = i < lines.length - 1 ? lines[i + 1]?.trim() : ''
1933-
const shouldContinue = bracketDepth > 0 || angleDepth > 0
1934-
|| (nextLine && !nextLine.startsWith('export') && !nextLine.startsWith('interface'))
1935-
1936-
if (!shouldContinue || isComplete) {
1937-
debugLog('declaration-complete', `Declaration complete at line ${i + 1}`)
1938-
processBlock(currentBlock, currentComments, state)
1939-
currentBlock = []
1940-
currentComments = []
1941-
inDeclaration = false
1942-
bracketDepth = 0
1943-
angleDepth = 0
1927+
// Special handling for type declarations
1928+
const isTypeDeclaration = currentBlock[0].trim().startsWith('type')
1929+
|| currentBlock[0].trim().startsWith('export type')
1930+
1931+
if (isTypeDeclaration) {
1932+
// For type declarations, we need to track the complete expression
1933+
const nextLine = i < lines.length - 1 ? lines[i + 1]?.trim() : ''
1934+
const shouldContinue = bracketDepth > 0 || angleDepth > 0
1935+
|| !trimmedLine.endsWith(';') // No semicolon yet
1936+
|| trimmedLine.endsWith('?') // Conditional type continues
1937+
|| trimmedLine.endsWith(':') // Property type continues
1938+
|| (nextLine && (
1939+
nextLine.startsWith('?')
1940+
|| nextLine.startsWith(':')
1941+
|| nextLine.startsWith('|')
1942+
|| nextLine.startsWith('&')
1943+
|| nextLine.startsWith('extends')
1944+
|| nextLine.startsWith('=>')
1945+
))
1946+
1947+
if (!shouldContinue) {
1948+
debugLog('declaration-complete', `Type declaration complete at line ${i + 1}`)
1949+
processBlock(currentBlock, currentComments, state)
1950+
currentBlock = []
1951+
currentComments = []
1952+
inDeclaration = false
1953+
bracketDepth = 0
1954+
angleDepth = 0
1955+
}
1956+
}
1957+
else {
1958+
// Original handling for non-type declarations
1959+
const isComplete = bracketDepth === 0 && angleDepth === 0 && trimmedLine.endsWith('}')
1960+
const nextLine = i < lines.length - 1 ? lines[i + 1]?.trim() : ''
1961+
const shouldContinue = bracketDepth > 0 || angleDepth > 0
1962+
|| (nextLine && !nextLine.startsWith('export') && !nextLine.startsWith('interface'))
1963+
1964+
if (!shouldContinue || isComplete) {
1965+
debugLog('declaration-complete', `Declaration complete at line ${i + 1}`)
1966+
processBlock(currentBlock, currentComments, state)
1967+
currentBlock = []
1968+
currentComments = []
1969+
inDeclaration = false
1970+
bracketDepth = 0
1971+
angleDepth = 0
1972+
}
19441973
}
19451974
}
19461975
}

0 commit comments

Comments
 (0)