diff --git a/.changelog/5978-fix-shipped-typings.md b/.changelog/5978-fix-shipped-typings.md new file mode 100644 index 0000000000..52584b3d3e --- /dev/null +++ b/.changelog/5978-fix-shipped-typings.md @@ -0,0 +1,3 @@ +### Fixed + +- Fixed type errors in the published typings when `skipLibCheck` is turned off, in PR [#5978](https://github.com/microsoft/BotFramework-WebChat/pull/5978), by [@OEvgeny](https://github.com/OEvgeny) diff --git a/packages/api/src/decorator/private/templateDecorator.tsx b/packages/api/src/decorator/private/templateDecorator.tsx index cb80e1f6c6..f3ec6d2138 100644 --- a/packages/api/src/decorator/private/templateDecorator.tsx +++ b/packages/api/src/decorator/private/templateDecorator.tsx @@ -108,6 +108,11 @@ export default function templateDecorator< }; } -export type InferMiddleware> = T['~types']['middleware']; -export type InferProps> = T['~types']['props']; -export type InferRequest> = T['~types']['request']; +// Only constrain on `~types`: under `strictFunctionTypes`, a template with specific props is not assignable to `ReturnType`. +type TemplateDecoratorTypes = { + readonly '~types': { readonly middleware: unknown; readonly props: unknown; readonly request: unknown }; +}; + +export type InferMiddleware = T['~types']['middleware']; +export type InferProps = T['~types']['props']; +export type InferRequest = T['~types']['request']; diff --git a/packages/api/src/types/WebSpeechPonyfill.ts b/packages/api/src/types/WebSpeechPonyfill.ts index dee36f7948..272555a23a 100644 --- a/packages/api/src/types/WebSpeechPonyfill.ts +++ b/packages/api/src/types/WebSpeechPonyfill.ts @@ -1,4 +1,9 @@ -/* globals SpeechGrammarList, SpeechRecognition, SpeechSynthesis */ +/* globals SpeechSynthesis */ + +import { type TypeOfGlobal } from '@msinternal/botframework-webchat-base/utils'; + +// `SpeechGrammarList` and `SpeechRecognition` are not in TypeScript's DOM library, they come from `@types/dom-speech-recognition`. +// Use `typeof SpeechGrammarList`/`typeof SpeechRecognition` again when TypeScript's DOM library includes them. type WebSpeechPonyfill = { /** @@ -9,10 +14,10 @@ type WebSpeechPonyfill = { resumeAudioContext?: () => Promise; /** Polyfill for Web Speech API `SpeechGrammarList` class. */ - SpeechGrammarList?: typeof SpeechGrammarList; + SpeechGrammarList?: TypeOfGlobal<'SpeechGrammarList', new () => object>; /** Polyfill for Web Speech API `SpeechRecognition` class. */ - SpeechRecognition?: typeof SpeechRecognition; + SpeechRecognition?: TypeOfGlobal<'SpeechRecognition', new () => object>; /** Polyfill for Web Speech API `speechSynthesis` instance. */ speechSynthesis?: SpeechSynthesis; diff --git a/packages/base/src/utils/TypeOfGlobal.ts b/packages/base/src/utils/TypeOfGlobal.ts new file mode 100644 index 0000000000..a6f4ef5ff8 --- /dev/null +++ b/packages/base/src/utils/TypeOfGlobal.ts @@ -0,0 +1,10 @@ +/** + * Type of a global, or `Fallback` if the consumer's global types do not declare it. + * + * Use this instead of `typeof X` in published typings when `X` is not in TypeScript's DOM library, e.g. `setImmediate` + * (Node.js types) or `SpeechRecognition` (`@types/dom-speech-recognition`), so consumers without these types do not get + * "Cannot find name". + */ +type TypeOfGlobal = typeof globalThis extends Record ? T : Fallback; + +export { type TypeOfGlobal }; diff --git a/packages/base/src/utils/index.ts b/packages/base/src/utils/index.ts index ab2260fd7d..5d0a2be96e 100644 --- a/packages/base/src/utils/index.ts +++ b/packages/base/src/utils/index.ts @@ -6,5 +6,6 @@ export { default as iterateEquals } from './iterateEquals'; export { type OneOrMany } from './OneOrMany'; export { default as singleToArray } from './singleToArray'; export { default as toSpliced } from './toSpliced'; +export { type TypeOfGlobal } from './TypeOfGlobal'; export { default as warnOnce } from './warnOnce'; export { default as withResolvers, type PromiseWithResolvers } from './withResolvers'; diff --git a/packages/bundle/src/boot/actual/component/minimal.ts b/packages/bundle/src/boot/actual/component/minimal.ts index ceadf00b3b..81a4bd4a7d 100644 --- a/packages/bundle/src/boot/actual/component/minimal.ts +++ b/packages/bundle/src/boot/actual/component/minimal.ts @@ -31,8 +31,5 @@ export { UploadButton, VideoContent, VimeoContent, - YouTubeContent, - type BasicWebChatProps, - type ComposerProps, - type ReactWebChatProps + YouTubeContent } from 'botframework-webchat-component/component.js'; diff --git a/packages/bundle/src/boot/actual/decorator.ts b/packages/bundle/src/boot/actual/decorator.ts index 7052e86704..d42530ac34 100644 --- a/packages/bundle/src/boot/actual/decorator.ts +++ b/packages/bundle/src/boot/actual/decorator.ts @@ -5,9 +5,6 @@ export { createActivityBorderMiddleware, createActivityGroupingMiddleware, DecoratorComposer, - useDecoratorRequest, - type ActivityBorderDecoratorProps, - type DecoratorMiddleware, - type InferDecoratorRequest + useDecoratorRequest } from 'botframework-webchat-api/decorator.js'; export { BorderFlair, BorderLoader, WebChatDecorator } from 'botframework-webchat-component/decorator.js'; diff --git a/packages/bundle/src/boot/actual/hook/minimal.ts b/packages/bundle/src/boot/actual/hook/minimal.ts index 4f45c9575f..45425eb16f 100644 --- a/packages/bundle/src/boot/actual/hook/minimal.ts +++ b/packages/bundle/src/boot/actual/hook/minimal.ts @@ -100,7 +100,5 @@ export { useVoiceRecordingMuted, useVoiceSelector, useVoiceState, - useWebSpeechPonyfill, - type DropZoneState, - type SendBoxFocusOptions + useWebSpeechPonyfill } from 'botframework-webchat-component/hook.js'; diff --git a/packages/bundle/src/boot/actual/internal.ts b/packages/bundle/src/boot/actual/internal.ts index 394a48c44e..fc8c411144 100644 --- a/packages/bundle/src/boot/actual/internal.ts +++ b/packages/bundle/src/boot/actual/internal.ts @@ -1,9 +1,4 @@ // We should review exports in this file to make sure 1P = 3P. -export { - type ActivityMiddleware, - type ActivityStatusMiddleware, - type TypingIndicatorMiddleware -} from 'botframework-webchat-api'; export { usePostVoiceActivity, useShouldShowMicrophoneButton } from 'botframework-webchat-api/internal.js'; export { CodeHighlighterComposer, @@ -16,14 +11,11 @@ export { serializeDocumentFragmentIntoString, useActivityStyleOptions, useCodeHighlighter, - useLiveRegion, - type HighlightCodeFn + useLiveRegion } from 'botframework-webchat-component/internal.js'; export { getOrgSchemaMessage, getVoiceActivityRole, getVoiceActivityText, - isVoiceTranscriptActivity, - type DirectLineCardAction, - type WebChatActivity + isVoiceTranscriptActivity } from 'botframework-webchat-core'; diff --git a/packages/bundle/src/boot/actual/minimal.ts b/packages/bundle/src/boot/actual/minimal.ts index b6f82d3ef0..78a3a85a66 100644 --- a/packages/bundle/src/boot/actual/minimal.ts +++ b/packages/bundle/src/boot/actual/minimal.ts @@ -7,9 +7,10 @@ const { object: buildInfoObject, version } = buildInfo; // #endregion export { concatMiddleware, createStyleSet, testIds, withEmoji } from 'botframework-webchat-component'; +export { type ReactWebChatProps } from 'botframework-webchat-component/component.js'; export { Constants, createStore, createStoreWithDevTools, createStoreWithOptions } from 'botframework-webchat-core'; export { default as createBrowserWebSpeechPonyfillFactory } from '../../createBrowserWebSpeechPonyfillFactory'; -export { ReactWebChat, type ReactWebChatProps } from './component/minimal'; +export { ReactWebChat } from './component/minimal'; export { default as createDirectLine } from './private/createDirectLine'; export { default as createDirectLineAppServiceExtension } from './private/createDirectLineAppServiceExtension'; export { renderWebChat } from './renderWebChat/minimal'; diff --git a/packages/bundle/src/boot/exports/component.ts b/packages/bundle/src/boot/exports/component.ts index e82ed79727..c99d73d1cf 100644 --- a/packages/bundle/src/boot/exports/component.ts +++ b/packages/bundle/src/boot/exports/component.ts @@ -1 +1,8 @@ export * from '../actual/component/full'; + +// Types are exported here instead of `../actual/component/minimal`, see the namespaces in `./minimal.ts`. +export { + type BasicWebChatProps, + type ComposerProps, + type ReactWebChatProps +} from 'botframework-webchat-component/component.js'; diff --git a/packages/bundle/src/boot/exports/decorator.ts b/packages/bundle/src/boot/exports/decorator.ts index 0c659581dd..52aea59e44 100644 --- a/packages/bundle/src/boot/exports/decorator.ts +++ b/packages/bundle/src/boot/exports/decorator.ts @@ -1 +1,8 @@ export * from '../actual/decorator'; + +// Types are exported here instead of `../actual/decorator`, see the namespaces in `./minimal.ts`. +export { + type ActivityBorderDecoratorProps, + type DecoratorMiddleware, + type InferDecoratorRequest +} from 'botframework-webchat-api/decorator.js'; diff --git a/packages/bundle/src/boot/exports/hook.ts b/packages/bundle/src/boot/exports/hook.ts index e2b1e978be..98b84b85a7 100644 --- a/packages/bundle/src/boot/exports/hook.ts +++ b/packages/bundle/src/boot/exports/hook.ts @@ -1 +1,4 @@ export * from '../actual/hook/full'; + +// Types are exported here instead of `../actual/hook/minimal`, see the namespaces in `./minimal.ts`. +export { type DropZoneState, type SendBoxFocusOptions } from 'botframework-webchat-component/hook.js'; diff --git a/packages/bundle/src/boot/exports/internal.ts b/packages/bundle/src/boot/exports/internal.ts index af61492c07..0bd96909da 100644 --- a/packages/bundle/src/boot/exports/internal.ts +++ b/packages/bundle/src/boot/exports/internal.ts @@ -1 +1,10 @@ export * from '../actual/internal'; + +// Types are exported here instead of `../actual/internal`, see the namespaces in `./minimal.ts`. +export { + type ActivityMiddleware, + type ActivityStatusMiddleware, + type TypingIndicatorMiddleware +} from 'botframework-webchat-api'; +export { type HighlightCodeFn } from 'botframework-webchat-component/internal.js'; +export { type DirectLineCardAction, type WebChatActivity } from 'botframework-webchat-core'; diff --git a/packages/bundle/src/boot/exports/minimal.ts b/packages/bundle/src/boot/exports/minimal.ts index c0f67e7f6c..3b02e91c6f 100644 --- a/packages/bundle/src/boot/exports/minimal.ts +++ b/packages/bundle/src/boot/exports/minimal.ts @@ -3,6 +3,8 @@ export { ReactWebChat as default } from '../actual/minimal'; // export * does no // #region Backward compatibility // Web devs should move to named exports instead. +// Keep types out of these namespaces until rollup-plugin-dts (used by tsup) emits types imported from another package as types: +// it emits them as `declare const X: typeof X`, which fails type checking (TS2693). Entry points export them instead, e.g. `./decorator.ts`. export * as Components from '../actual/component/minimal'; export * as decorator from '../actual/decorator'; export * as hooks from '../actual/hook/minimal'; diff --git a/packages/bundle/src/markdown/createStreamingRenderer.spec.ts b/packages/bundle/src/markdown/createMarkdownStreamingRenderer.spec.ts similarity index 98% rename from packages/bundle/src/markdown/createStreamingRenderer.spec.ts rename to packages/bundle/src/markdown/createMarkdownStreamingRenderer.spec.ts index 02f557d3e7..9f08a30a23 100644 --- a/packages/bundle/src/markdown/createStreamingRenderer.spec.ts +++ b/packages/bundle/src/markdown/createMarkdownStreamingRenderer.spec.ts @@ -1,13 +1,13 @@ /** @jest-environment @happy-dom/jest-environment */ /// -import createStreamingRenderer, { STREAMING_ERROR } from './createStreamingRenderer'; +import createMarkdownStreamingRenderer, { STREAMING_ERROR } from './createMarkdownStreamingRenderer'; -const OPTIONS: Parameters[0] = { +const OPTIONS: Parameters[0] = { markdownRespectCRLF: false }; -const INIT: Parameters[1] = { +const INIT: Parameters[1] = { externalLinkAlt: 'Opens in a new window' }; @@ -18,7 +18,7 @@ function setup() { document.body.appendChild(container); - const renderer = createStreamingRenderer(OPTIONS, INIT); + const renderer = createMarkdownStreamingRenderer(OPTIONS, INIT); currentContainer = container; @@ -80,7 +80,7 @@ function splitBySentinel(container: HTMLElement): [string, string] | null { return [committedDiv.innerHTML.trim(), activeDiv.innerHTML.trim()]; } -describe('createStreamingRenderer', () => { +describe('createMarkdownStreamingRenderer', () => { afterEach(() => { if (!currentContainer) { return; diff --git a/packages/bundle/src/markdown/createStreamingRenderer.ts b/packages/bundle/src/markdown/createMarkdownStreamingRenderer.ts similarity index 99% rename from packages/bundle/src/markdown/createStreamingRenderer.ts rename to packages/bundle/src/markdown/createMarkdownStreamingRenderer.ts index 68a535dc6a..576aaf4e1d 100644 --- a/packages/bundle/src/markdown/createStreamingRenderer.ts +++ b/packages/bundle/src/markdown/createMarkdownStreamingRenderer.ts @@ -87,7 +87,7 @@ function findTopLevelBlocks(events: ReadonlyArray): readonly BlockBoundar return blocks; } -export default function createStreamingRenderer( +export default function createMarkdownStreamingRenderer( { markdownRenderHTML, markdownRespectCRLF }: StreamingRenderOptions, { externalLinkAlt }: StreamingRenderInit ): StreamingRenderer { diff --git a/packages/bundle/src/markdown/renderMarkdown.ts b/packages/bundle/src/markdown/renderMarkdown.ts index d3a7896597..10e43ce6a3 100644 --- a/packages/bundle/src/markdown/renderMarkdown.ts +++ b/packages/bundle/src/markdown/renderMarkdown.ts @@ -8,12 +8,12 @@ import katex from 'katex'; import { micromark } from 'micromark'; import { gfm, gfmHtml } from 'micromark-extension-gfm'; -import createStreamingRenderer, { +import createMarkdownStreamingRenderer, { type StreamingNextOptions, type StreamingNextResult, type StreamingRenderer, type StreamingRenderOptions -} from './createStreamingRenderer'; +} from './createMarkdownStreamingRenderer'; import { math, mathHtml } from './mathExtension'; import { createDecorate } from './private/createDecorate'; import iterateLinkDefinitions from './private/iterateLinkDefinitions'; @@ -67,6 +67,7 @@ export default function render( return serializeDocumentFragmentIntoString(documentFragmentAfterMarkdown).trim(); } -render.createStreamingRenderer = createStreamingRenderer; +// The function is named differently than the property: in our typings, `typeof createStreamingRenderer` would refer to the property itself. +render.createStreamingRenderer = createMarkdownStreamingRenderer; export { type StreamingNextOptions, type StreamingNextResult, type StreamingRenderer, type StreamingRenderOptions }; diff --git a/packages/component/src/types/ContextOf.ts b/packages/component/src/types/ContextOf.ts index 2546f15502..b2d6a84bdd 100644 --- a/packages/component/src/types/ContextOf.ts +++ b/packages/component/src/types/ContextOf.ts @@ -1,5 +1,5 @@ import { type Context } from 'react'; -type ContextOf> = T extends Context ? C : never; +type ContextOf = T extends Context ? C : never; export type { ContextOf }; diff --git a/packages/core/src/types/internal/GlobalScopeClock.ts b/packages/core/src/types/internal/GlobalScopeClock.ts index 23b2a1733b..aea8e09db2 100644 --- a/packages/core/src/types/internal/GlobalScopeClock.ts +++ b/packages/core/src/types/internal/GlobalScopeClock.ts @@ -1,10 +1,13 @@ +import { type TypeOfGlobal } from '@msinternal/botframework-webchat-base/utils'; + export type GlobalScopeClock = { // eslint-disable-next-line no-restricted-globals cancelAnimationFrame?: typeof cancelAnimationFrame | undefined; // eslint-disable-next-line no-restricted-globals cancelIdleCallback?: typeof cancelIdleCallback | undefined; - // eslint-disable-next-line no-restricted-globals - clearImmediate?: typeof clearImmediate | undefined; + // `setImmediate` and `clearImmediate` are Node.js globals, not in TypeScript's DOM library. + // Fallbacks are the same types as in `env.d.ts`. + clearImmediate?: TypeOfGlobal<'clearImmediate', (timeout: number) => void> | undefined; // eslint-disable-next-line no-restricted-globals clearInterval?: typeof clearInterval | undefined; // eslint-disable-next-line no-restricted-globals @@ -15,8 +18,7 @@ export type GlobalScopeClock = { requestAnimationFrame?: typeof requestAnimationFrame | undefined; // eslint-disable-next-line no-restricted-globals requestIdleCallback?: typeof requestIdleCallback | undefined; - // eslint-disable-next-line no-restricted-globals - setImmediate?: typeof setImmediate | undefined; + setImmediate?: TypeOfGlobal<'setImmediate', (fn: () => void) => number> | undefined; // eslint-disable-next-line no-restricted-globals setInterval?: typeof setInterval | undefined; // eslint-disable-next-line no-restricted-globals