diff --git a/scripts/tasks/api-extractor.ts b/scripts/tasks/api-extractor.ts index c650e16a55eaad..83660fe908debd 100644 --- a/scripts/tasks/api-extractor.ts +++ b/scripts/tasks/api-extractor.ts @@ -101,7 +101,7 @@ export function apiExtractor() { } logger.info(`api-extractor: package is using TS path aliases. Overriding TS compiler settings.`); - const compilerConfig = getTsPathAliasesApiExtractorConfig({ tsConfig, tsConfigPath }); + const compilerConfig = getTsPathAliasesApiExtractorConfig({ tsConfig, tsConfigPath, packageJson }); config.compiler = compilerConfig; }, diff --git a/scripts/tasks/utils.ts b/scripts/tasks/utils.ts index 38b27901fe40f2..97d3174cdfa6ff 100644 --- a/scripts/tasks/utils.ts +++ b/scripts/tasks/utils.ts @@ -19,7 +19,33 @@ export function getTsPathAliasesConfig() { return { tsConfig, isUsingTsSolutionConfigs, tsConfigFile, tsConfigPath, packageJson }; } -export function getTsPathAliasesApiExtractorConfig(options: { tsConfig: TsConfig; tsConfigPath: string }) { +const packagesWithInvalidTypes = [ + /** + * @see @storybook/api/dist/ts3.9/lib/stories.d.ts:1:8 - `import React from 'react'` + */ + '@storybook/api', +]; + +/** + * Some 3rd party packages might ship invalid types for consumers that don't have synthetic default imports enabled + * In that case our package needs to have `allowSyntheticDefaultImports` to pass the TS lib check. + * + * NOTE: This is safe to use on type declaration level for following reasons: + * - it doesn't affect emitted runtime code + * - it doesn't affect our declaration types emit + */ +function enableAllowSyntheticDefaultImports(options: { pkgJson: PackageJson }) { + const dependencies = Object.keys({ ...options.pkgJson.dependencies, ...options.pkgJson.peerDependencies }); + const shouldEnable = dependencies.some(dependency => packagesWithInvalidTypes.includes(dependency)); + + return shouldEnable ? { allowSyntheticDefaultImports: true } : null; +} + +export function getTsPathAliasesApiExtractorConfig(options: { + tsConfig: TsConfig; + tsConfigPath: string; + packageJson: PackageJson; +}) { const rootOffset = offsetFromRoot(path.dirname(options.tsConfigPath.replace(appRootPath, ''))); /** * This special TSConfig config is all that's needed for api-extractor so it has all type information used for package: @@ -35,6 +61,7 @@ export function getTsPathAliasesApiExtractorConfig(options: { tsConfig: TsConfig */ ...(options.tsConfig.files ? { files: options.tsConfig.files } : null), compilerOptions: { + ...enableAllowSyntheticDefaultImports({ pkgJson: options.packageJson }), strict: true, lib: options.tsConfig.compilerOptions.lib, typeRoots: ['node_modules/@types', `${rootOffset}typings`], @@ -60,6 +87,7 @@ interface PackageJson { scripts?: Record; dependencies?: Record; devDependencies?: Record; + peerDependencies?: Record; } export interface TsConfig {