diff --git a/adev/src/app/app.config.server.ts b/adev/src/app/app.config.server.ts index c27edbb1845..cd3afd3c97b 100644 --- a/adev/src/app/app.config.server.ts +++ b/adev/src/app/app.config.server.ts @@ -14,4 +14,4 @@ const serverConfig: ApplicationConfig = { providers: [provideServerRendering(withRoutes([{path: '**', renderMode: RenderMode.Prerender}]))], }; -export const config = mergeApplicationConfig(appConfig, serverConfig); +export const config: ApplicationConfig = mergeApplicationConfig(appConfig, serverConfig); diff --git a/adev/src/app/routes.ts b/adev/src/app/routes.ts index 4f561e13583..2a4060c8e81 100644 --- a/adev/src/app/routes.ts +++ b/adev/src/app/routes.ts @@ -16,7 +16,7 @@ import MainComponent from './main.component'; // Docs navigation data contains routes which navigates to /tutorials pages, in // that case we should load Tutorial component -export const DOCS_ROUTES = mapNavigationItemsToRoutes( +export const DOCS_ROUTES: Route[] = mapNavigationItemsToRoutes( flatNavigationData(SUB_NAVIGATION_DATA.docs).filter( (route) => !route.path?.startsWith(PagePrefix.TUTORIALS) && route.path !== PagePrefix.PLAYGROUND, diff --git a/goldens/public-api/common/index.api.md b/goldens/public-api/common/index.api.md index 3e703e81b78..fa399abb00e 100644 --- a/goldens/public-api/common/index.api.md +++ b/goldens/public-api/common/index.api.md @@ -874,16 +874,16 @@ export { PopStateEvent_2 as PopStateEvent } export const PRECONNECT_CHECK_BLOCKLIST: InjectionToken<(string | string[])[]>; // @public -export const provideCloudflareLoader: (path: string) => i0.Provider[]; +export const provideCloudflareLoader: (path: string) => Provider[]; // @public -export const provideCloudinaryLoader: (path: string) => i0.Provider[]; +export const provideCloudinaryLoader: (path: string) => Provider[]; // @public -export const provideImageKitLoader: (path: string) => i0.Provider[]; +export const provideImageKitLoader: (path: string) => Provider[]; // @public -export const provideImgixLoader: (path: string) => i0.Provider[]; +export const provideImgixLoader: (path: string) => Provider[]; // @public export function provideNetlifyLoader(path?: string): Provider[]; diff --git a/goldens/public-api/platform-browser-dynamic/index.api.md b/goldens/public-api/platform-browser-dynamic/index.api.md index cc5f45d1fad..5129e504dff 100644 --- a/goldens/public-api/platform-browser-dynamic/index.api.md +++ b/goldens/public-api/platform-browser-dynamic/index.api.md @@ -7,7 +7,7 @@ import { Compiler } from '@angular/core'; import { CompilerFactory } from '@angular/core'; import { CompilerOptions } from '@angular/core'; -import * as i0 from '@angular/core'; +import { PlatformRef } from '@angular/core'; import { StaticProvider } from '@angular/core'; import { Version } from '@angular/core'; @@ -18,7 +18,7 @@ export class JitCompilerFactory implements CompilerFactory { } // @public (undocumented) -export const platformBrowserDynamic: (extraProviders?: StaticProvider[]) => i0.PlatformRef; +export const platformBrowserDynamic: (extraProviders?: StaticProvider[]) => PlatformRef; // @public (undocumented) export const VERSION: Version; diff --git a/goldens/public-api/platform-browser/testing/index.api.md b/goldens/public-api/platform-browser/testing/index.api.md index aef5cb15664..b4c362b05a2 100644 --- a/goldens/public-api/platform-browser/testing/index.api.md +++ b/goldens/public-api/platform-browser/testing/index.api.md @@ -6,6 +6,7 @@ import * as i0 from '@angular/core'; import * as i1 from '@angular/common'; +import { PlatformRef } from '@angular/core'; import { StaticProvider } from '@angular/core'; // @public @@ -19,7 +20,7 @@ export class BrowserTestingModule { } // @public -export const platformBrowserTesting: (extraProviders?: StaticProvider[]) => i0.PlatformRef; +export const platformBrowserTesting: (extraProviders?: StaticProvider[]) => PlatformRef; // (No @packageDocumentation comment for this package) diff --git a/goldens/public-api/platform-server/testing/index.api.md b/goldens/public-api/platform-server/testing/index.api.md index d6364590445..74b226cdcba 100644 --- a/goldens/public-api/platform-server/testing/index.api.md +++ b/goldens/public-api/platform-server/testing/index.api.md @@ -6,10 +6,11 @@ import * as i0 from '@angular/core'; import * as i1 from '@angular/platform-browser-dynamic/testing'; +import { PlatformRef } from '@angular/core'; import { StaticProvider } from '@angular/core'; // @public @deprecated -export const platformServerTesting: (extraProviders?: StaticProvider[]) => i0.PlatformRef; +export const platformServerTesting: (extraProviders?: StaticProvider[]) => PlatformRef; // @public @deprecated export class ServerTestingModule { diff --git a/modules/benchmarks/src/change_detection/util.ts b/modules/benchmarks/src/change_detection/util.ts index 4d6cb8dc475..73dca914778 100644 --- a/modules/benchmarks/src/change_detection/util.ts +++ b/modules/benchmarks/src/change_detection/util.ts @@ -8,7 +8,7 @@ import {getIntParameter} from '../util'; -export const numViews = getIntParameter('viewCount'); +export const numViews: number = getIntParameter('viewCount'); export function newArray(size: number): T[]; export function newArray(size: number, value: T): T[]; diff --git a/modules/ssr-benchmarks/src/app/app.config.server.ts b/modules/ssr-benchmarks/src/app/app.config.server.ts index 5fd01686705..4f60c86bfd5 100644 --- a/modules/ssr-benchmarks/src/app/app.config.server.ts +++ b/modules/ssr-benchmarks/src/app/app.config.server.ts @@ -14,4 +14,4 @@ const serverConfig: ApplicationConfig = { providers: [provideServerRendering()], }; -export const config = mergeApplicationConfig(appConfig, serverConfig); +export const config: ApplicationConfig = mergeApplicationConfig(appConfig, serverConfig); diff --git a/packages/common/src/directives/ng_optimized_image/image_loaders/cloudflare_loader.ts b/packages/common/src/directives/ng_optimized_image/image_loaders/cloudflare_loader.ts index 8508a5349a2..5e5a25939ea 100644 --- a/packages/common/src/directives/ng_optimized_image/image_loaders/cloudflare_loader.ts +++ b/packages/common/src/directives/ng_optimized_image/image_loaders/cloudflare_loader.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import {Provider} from '@angular/core'; import {PLACEHOLDER_QUALITY} from './constants'; import {createImageLoader, ImageLoaderConfig} from './image_loader'; @@ -20,7 +21,7 @@ import {createImageLoader, ImageLoaderConfig} from './image_loader'; * * @publicApi */ -export const provideCloudflareLoader = createImageLoader( +export const provideCloudflareLoader: (path: string) => Provider[] = createImageLoader( createCloudflareUrl, ngDevMode ? ['https:///cdn-cgi/image//'] : undefined, ); diff --git a/packages/common/src/directives/ng_optimized_image/image_loaders/cloudinary_loader.ts b/packages/common/src/directives/ng_optimized_image/image_loaders/cloudinary_loader.ts index f3a6b852804..cfee85bf9fa 100644 --- a/packages/common/src/directives/ng_optimized_image/image_loaders/cloudinary_loader.ts +++ b/packages/common/src/directives/ng_optimized_image/image_loaders/cloudinary_loader.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import {Provider} from '@angular/core'; import {createImageLoader, ImageLoaderConfig, ImageLoaderInfo} from './image_loader'; /** @@ -36,7 +37,7 @@ function isCloudinaryUrl(url: string): boolean { * * @publicApi */ -export const provideCloudinaryLoader = createImageLoader( +export const provideCloudinaryLoader: (path: string) => Provider[] = createImageLoader( createCloudinaryUrl, ngDevMode ? [ diff --git a/packages/common/src/directives/ng_optimized_image/image_loaders/imagekit_loader.ts b/packages/common/src/directives/ng_optimized_image/image_loaders/imagekit_loader.ts index af50ff5223c..341cf4cf8f4 100644 --- a/packages/common/src/directives/ng_optimized_image/image_loaders/imagekit_loader.ts +++ b/packages/common/src/directives/ng_optimized_image/image_loaders/imagekit_loader.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import {Provider} from '@angular/core'; import {PLACEHOLDER_QUALITY} from './constants'; import {createImageLoader, ImageLoaderConfig, ImageLoaderInfo} from './image_loader'; @@ -36,7 +37,7 @@ function isImageKitUrl(url: string): boolean { * * @publicApi */ -export const provideImageKitLoader = createImageLoader( +export const provideImageKitLoader: (path: string) => Provider[] = createImageLoader( createImagekitUrl, ngDevMode ? ['https://ik.imagekit.io/mysite', 'https://subdomain.mysite.com'] : undefined, ); diff --git a/packages/common/src/directives/ng_optimized_image/image_loaders/imgix_loader.ts b/packages/common/src/directives/ng_optimized_image/image_loaders/imgix_loader.ts index 6830404441e..561437cb903 100644 --- a/packages/common/src/directives/ng_optimized_image/image_loaders/imgix_loader.ts +++ b/packages/common/src/directives/ng_optimized_image/image_loaders/imgix_loader.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ +import {Provider} from '@angular/core'; import {PLACEHOLDER_QUALITY} from './constants'; import {createImageLoader, ImageLoaderConfig, ImageLoaderInfo} from './image_loader'; @@ -34,7 +35,7 @@ function isImgixUrl(url: string): boolean { * * @publicApi */ -export const provideImgixLoader = createImageLoader( +export const provideImgixLoader: (path: string) => Provider[] = createImageLoader( createImgixUrl, ngDevMode ? ['https://somepath.imgix.net/'] : undefined, ); diff --git a/packages/compiler-cli/src/ngtsc/annotations/directive/src/query_functions.ts b/packages/compiler-cli/src/ngtsc/annotations/directive/src/query_functions.ts index 28520770c86..e3e3b723681 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/directive/src/query_functions.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/directive/src/query_functions.ts @@ -26,7 +26,7 @@ import { import {tryUnwrapForwardRef} from '../../common'; import {validateAccessOfInitializerApiMember} from './initializer_function_access'; -import {tryParseInitializerApi} from './initializer_functions'; +import {InitializerApiFunction, tryParseInitializerApi} from './initializer_functions'; /** Possible query initializer API functions. */ export type QueryFunctionName = 'viewChild' | 'contentChild' | 'viewChildren' | 'contentChildren'; @@ -40,20 +40,21 @@ const queryFunctionNames: QueryFunctionName[] = [ ]; /** Possible query initializer API functions. */ -export const QUERY_INITIALIZER_FNS = queryFunctionNames.map((fnName) => ({ - functionName: fnName, - owningModule: '@angular/core' as const, - // Queries are accessed from within static blocks, via the query definition functions. - // Conceptually, the fields could access private members— even ES private fields. - // Support for ES private fields requires special caution and complexity when partial - // output is linked— hence not supported. TS private members are allowed in static blocks. - allowedAccessLevels: [ - ClassMemberAccessLevel.PublicWritable, - ClassMemberAccessLevel.PublicReadonly, - ClassMemberAccessLevel.Protected, - ClassMemberAccessLevel.Private, - ], -})); +export const QUERY_INITIALIZER_FNS: (InitializerApiFunction & {functionName: QueryFunctionName})[] = + queryFunctionNames.map((fnName) => ({ + functionName: fnName, + owningModule: '@angular/core' as const, + // Queries are accessed from within static blocks, via the query definition functions. + // Conceptually, the fields could access private members— even ES private fields. + // Support for ES private fields requires special caution and complexity when partial + // output is linked— hence not supported. TS private members are allowed in static blocks. + allowedAccessLevels: [ + ClassMemberAccessLevel.PublicWritable, + ClassMemberAccessLevel.PublicReadonly, + ClassMemberAccessLevel.Protected, + ClassMemberAccessLevel.Private, + ], + })); // The `descendants` option is enabled by default, except for content children. const defaultDescendantsValue = (type: QueryFunctionName) => type !== 'contentChildren'; diff --git a/packages/compiler-cli/src/ngtsc/program_driver/src/api.ts b/packages/compiler-cli/src/ngtsc/program_driver/src/api.ts index 5e4f9b9dfbe..8a388df6aa4 100644 --- a/packages/compiler-cli/src/ngtsc/program_driver/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/program_driver/src/api.ts @@ -22,7 +22,7 @@ export interface FileUpdate { originalFile: ts.SourceFile | null; } -export const NgOriginalFile = Symbol('NgOriginalFile'); +export const NgOriginalFile: unique symbol = Symbol('NgOriginalFile'); /** * If an updated file has an associated original source file, then the original source file diff --git a/packages/compiler-cli/src/ngtsc/shims/src/expando.ts b/packages/compiler-cli/src/ngtsc/shims/src/expando.ts index 2a58bcd8b67..91a1fac1608 100644 --- a/packages/compiler-cli/src/ngtsc/shims/src/expando.ts +++ b/packages/compiler-cli/src/ngtsc/shims/src/expando.ts @@ -13,7 +13,7 @@ import {AbsoluteFsPath} from '../../file_system'; /** * A `Symbol` which is used to patch extension data onto `ts.SourceFile`s. */ -export const NgExtension = Symbol('NgExtension'); +export const NgExtension: unique symbol = Symbol('NgExtension'); /** * Contents of the `NgExtension` property of a `ts.SourceFile`. diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts index 3f8ae8ce0f9..3ea7b6d06bb 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/expression.ts @@ -54,7 +54,7 @@ import {tsCastToAny, tsNumericExpression} from './ts_util'; * - Some flavor of function call, like `isNan(0) as any` - requires even more characters than the * NaN option and has the same issue with `noLib`. */ -export const ANY_EXPRESSION = ts.factory.createAsExpression( +export const ANY_EXPRESSION: ts.AsExpression = ts.factory.createAsExpression( ts.factory.createNumericLiteral('0'), ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), ); diff --git a/packages/compiler/src/template/pipeline/ir/src/traits.ts b/packages/compiler/src/template/pipeline/ir/src/traits.ts index a5783de7434..8da07824794 100644 --- a/packages/compiler/src/template/pipeline/ir/src/traits.ts +++ b/packages/compiler/src/template/pipeline/ir/src/traits.ts @@ -15,22 +15,22 @@ import {SlotHandle} from './handle'; /** * Marker symbol for `ConsumesSlotOpTrait`. */ -export const ConsumesSlot = Symbol('ConsumesSlot'); +export const ConsumesSlot: unique symbol = Symbol('ConsumesSlot'); /** * Marker symbol for `DependsOnSlotContextOpTrait`. */ -export const DependsOnSlotContext = Symbol('DependsOnSlotContext'); +export const DependsOnSlotContext: unique symbol = Symbol('DependsOnSlotContext'); /** * Marker symbol for `ConsumesVars` trait. */ -export const ConsumesVarsTrait = Symbol('ConsumesVars'); +export const ConsumesVarsTrait: unique symbol = Symbol('ConsumesVars'); /** * Marker symbol for `UsesVarOffset` trait. */ -export const UsesVarOffset = Symbol('UsesVarOffset'); +export const UsesVarOffset: unique symbol = Symbol('UsesVarOffset'); /** * Marks an operation as requiring allocation of one or more data slots for storage. diff --git a/packages/core/primitives/event-dispatch/src/event_dispatcher.ts b/packages/core/primitives/event-dispatch/src/event_dispatcher.ts index 839d2d8a111..a859bfd1e23 100644 --- a/packages/core/primitives/event-dispatch/src/event_dispatcher.ts +++ b/packages/core/primitives/event-dispatch/src/event_dispatcher.ts @@ -19,7 +19,8 @@ import {Restriction} from './restriction'; export type Replayer = (eventInfoWrappers: Event[]) => void; /** An internal symbol used to indicate whether propagation should be stopped or not. */ -export const PROPAGATION_STOPPED_SYMBOL = /* @__PURE__ */ Symbol.for('propagationStopped'); +export const PROPAGATION_STOPPED_SYMBOL: unique symbol = + /* @__PURE__ */ Symbol.for('propagationStopped'); /** Extra event phases beyond what the browser provides. */ export const EventPhase = { diff --git a/packages/core/primitives/signals/src/graph.ts b/packages/core/primitives/signals/src/graph.ts index 52667b34116..40e1bc4a58c 100644 --- a/packages/core/primitives/signals/src/graph.ts +++ b/packages/core/primitives/signals/src/graph.ts @@ -37,7 +37,7 @@ let postProducerCreatedFn: ReactiveHookFn | null = null; * * This can be used to auto-unwrap signals in various cases, or to auto-wrap non-signal values. */ -export const SIGNAL = /* @__PURE__ */ Symbol('SIGNAL'); +export const SIGNAL: unique symbol = /* @__PURE__ */ Symbol('SIGNAL'); export function setActiveConsumer(consumer: ReactiveNode | null): ReactiveNode | null { const prev = activeConsumer; diff --git a/packages/core/primitives/signals/src/linked_signal.ts b/packages/core/primitives/signals/src/linked_signal.ts index 9f940992690..230c1b85ddb 100644 --- a/packages/core/primitives/signals/src/linked_signal.ts +++ b/packages/core/primitives/signals/src/linked_signal.ts @@ -119,7 +119,7 @@ export function linkedSignalUpdateFn( // Note: Using an IIFE here to ensure that the spread assignment is not considered // a side-effect, ending up preserving `LINKED_SIGNAL_NODE` and `REACTIVE_NODE`. // TODO: remove when https://github.com/evanw/esbuild/issues/3392 is resolved. -export const LINKED_SIGNAL_NODE = /* @__PURE__ */ (() => { +export const LINKED_SIGNAL_NODE: object = /* @__PURE__ */ (() => { return { ...REACTIVE_NODE, value: UNSET, diff --git a/packages/core/schematics/migrations/signal-migration/src/utils/is_identifier_free_in_scope.ts b/packages/core/schematics/migrations/signal-migration/src/utils/is_identifier_free_in_scope.ts index ea5ed640c5a..d483e21ec31 100644 --- a/packages/core/schematics/migrations/signal-migration/src/utils/is_identifier_free_in_scope.ts +++ b/packages/core/schematics/migrations/signal-migration/src/utils/is_identifier_free_in_scope.ts @@ -11,7 +11,7 @@ import ts from 'typescript'; import {isNodeDescendantOf} from './is_descendant_of'; /** Symbol that can be used to mark a variable as reserved, synthetically. */ -export const ReservedMarker = Symbol(); +export const ReservedMarker: unique symbol = Symbol(); // typescript/stable/src/compiler/types.ts;l=967;rcl=651008033 export interface LocalsContainer extends ts.Node { diff --git a/packages/core/src/authoring/input/input_signal.ts b/packages/core/src/authoring/input/input_signal.ts index 70cc3ebbbcc..42e70225487 100644 --- a/packages/core/src/authoring/input/input_signal.ts +++ b/packages/core/src/authoring/input/input_signal.ts @@ -57,8 +57,8 @@ export type InputOptionsWithTransform = Required< > & InputOptions; -export const ɵINPUT_SIGNAL_BRAND_READ_TYPE = /* @__PURE__ */ Symbol(); -export const ɵINPUT_SIGNAL_BRAND_WRITE_TYPE = /* @__PURE__ */ Symbol(); +export const ɵINPUT_SIGNAL_BRAND_READ_TYPE: unique symbol = /* @__PURE__ */ Symbol(); +export const ɵINPUT_SIGNAL_BRAND_WRITE_TYPE: unique symbol = /* @__PURE__ */ Symbol(); /** * `InputSignalWithTransform` represents a special `Signal` for a diff --git a/packages/core/src/authoring/input/input_signal_node.ts b/packages/core/src/authoring/input/input_signal_node.ts index ed1bbdc20e0..b521545b1a3 100644 --- a/packages/core/src/authoring/input/input_signal_node.ts +++ b/packages/core/src/authoring/input/input_signal_node.ts @@ -8,7 +8,7 @@ import {SIGNAL_NODE, SignalNode, signalSetFn} from '../../../primitives/signals'; -export const REQUIRED_UNSET_VALUE = /* @__PURE__ */ Symbol('InputSignalNode#UNSET'); +export const REQUIRED_UNSET_VALUE: unique symbol = /* @__PURE__ */ Symbol('InputSignalNode#UNSET'); /** * Reactive node type for an input signal. An input signal extends a signal. diff --git a/packages/core/src/di/interface/defs.ts b/packages/core/src/di/interface/defs.ts index f45c6c7224e..f90ac24249b 100644 --- a/packages/core/src/di/interface/defs.ts +++ b/packages/core/src/di/interface/defs.ts @@ -261,5 +261,5 @@ export function getInjectorDef(type: any): ɵɵInjectorDef | null { return type && type.hasOwnProperty(NG_INJ_DEF) ? (type as any)[NG_INJ_DEF] : null; } -export const NG_PROV_DEF = getClosureSafeProperty({ɵprov: getClosureSafeProperty}); -export const NG_INJ_DEF = getClosureSafeProperty({ɵinj: getClosureSafeProperty}); +export const NG_PROV_DEF: string = getClosureSafeProperty({ɵprov: getClosureSafeProperty}); +export const NG_INJ_DEF: string = getClosureSafeProperty({ɵinj: getClosureSafeProperty}); diff --git a/packages/core/src/di/provider_collection.ts b/packages/core/src/di/provider_collection.ts index 4a81ae0e6c2..9e13eb2aa45 100644 --- a/packages/core/src/di/provider_collection.ts +++ b/packages/core/src/di/provider_collection.ts @@ -403,7 +403,7 @@ function deepForEachProvider( } } -export const USE_VALUE = getClosureSafeProperty({ +export const USE_VALUE: string = getClosureSafeProperty({ provide: String, useValue: getClosureSafeProperty, }); diff --git a/packages/core/src/hydration/utils.ts b/packages/core/src/hydration/utils.ts index 672b5e9e48c..c0ec8f33d04 100644 --- a/packages/core/src/hydration/utils.ts +++ b/packages/core/src/hydration/utils.ts @@ -14,7 +14,7 @@ import {getDocument} from '../render3/interfaces/document'; import {RElement, RNode} from '../render3/interfaces/renderer_dom'; import {isRootView} from '../render3/interfaces/type_checks'; import {HEADER_OFFSET, LView, TVIEW, TViewType} from '../render3/interfaces/view'; -import {makeStateKey, TransferState} from '../transfer_state'; +import {makeStateKey, StateKey, TransferState} from '../transfer_state'; import {assertDefined, assertEqual} from '../util/assert'; import type {HydrationContext} from './annotate'; @@ -49,7 +49,8 @@ const TRANSFER_STATE_TOKEN_ID = '__nghData__'; /** * Lookup key used to reference DOM hydration data (ngh) in `TransferState`. */ -export const NGH_DATA_KEY = makeStateKey>(TRANSFER_STATE_TOKEN_ID); +export const NGH_DATA_KEY: StateKey = + makeStateKey>(TRANSFER_STATE_TOKEN_ID); /** * The name of the key used in the TransferState collection, @@ -60,9 +61,9 @@ export const TRANSFER_STATE_DEFER_BLOCKS_INFO = '__nghDeferData__'; /** * Lookup key used to retrieve defer block datain `TransferState`. */ -export const NGH_DEFER_BLOCKS_KEY = makeStateKey<{[key: string]: SerializedDeferBlock}>( - TRANSFER_STATE_DEFER_BLOCKS_INFO, -); +export const NGH_DEFER_BLOCKS_KEY: StateKey<{[key: string]: SerializedDeferBlock}> = makeStateKey<{ + [key: string]: SerializedDeferBlock; +}>(TRANSFER_STATE_DEFER_BLOCKS_INFO); /** * The name of the attribute that would be added to host component diff --git a/packages/core/src/render3/after_render/manager.ts b/packages/core/src/render3/after_render/manager.ts index 79c5264eec9..9a4e4e56395 100644 --- a/packages/core/src/render3/after_render/manager.ts +++ b/packages/core/src/render3/after_render/manager.ts @@ -37,7 +37,7 @@ export class AfterRenderManager { }); } -export const AFTER_RENDER_PHASES = /* @__PURE__ **/ (() => +export const AFTER_RENDER_PHASES: AfterRenderPhase[] = /* @__PURE__ **/ (() => [ AfterRenderPhase.EarlyRead, AfterRenderPhase.Write, diff --git a/packages/core/src/render3/dynamic_bindings.ts b/packages/core/src/render3/dynamic_bindings.ts index ba925c18b33..6f887a97fe5 100644 --- a/packages/core/src/render3/dynamic_bindings.ts +++ b/packages/core/src/render3/dynamic_bindings.ts @@ -18,7 +18,7 @@ import {stringifyForError} from './util/stringify_utils'; import {createOutputListener} from './view/directive_outputs'; /** Symbol used to store and retrieve metadata about a binding. */ -export const BINDING = /* @__PURE__ */ Symbol('BINDING'); +export const BINDING: unique symbol = /* @__PURE__ */ Symbol('BINDING'); /** * A dynamically-defined binding targeting. diff --git a/packages/core/src/render3/fields.ts b/packages/core/src/render3/fields.ts index a6792d4d927..9e840ebb48f 100644 --- a/packages/core/src/render3/fields.ts +++ b/packages/core/src/render3/fields.ts @@ -8,11 +8,11 @@ import {getClosureSafeProperty} from '../util/property'; -export const NG_COMP_DEF = getClosureSafeProperty({ɵcmp: getClosureSafeProperty}); -export const NG_DIR_DEF = getClosureSafeProperty({ɵdir: getClosureSafeProperty}); -export const NG_PIPE_DEF = getClosureSafeProperty({ɵpipe: getClosureSafeProperty}); -export const NG_MOD_DEF = getClosureSafeProperty({ɵmod: getClosureSafeProperty}); -export const NG_FACTORY_DEF = getClosureSafeProperty({ɵfac: getClosureSafeProperty}); +export const NG_COMP_DEF: string = getClosureSafeProperty({ɵcmp: getClosureSafeProperty}); +export const NG_DIR_DEF: string = getClosureSafeProperty({ɵdir: getClosureSafeProperty}); +export const NG_PIPE_DEF: string = getClosureSafeProperty({ɵpipe: getClosureSafeProperty}); +export const NG_MOD_DEF: string = getClosureSafeProperty({ɵmod: getClosureSafeProperty}); +export const NG_FACTORY_DEF: string = getClosureSafeProperty({ɵfac: getClosureSafeProperty}); /** * If a directive is diPublic, bloomAdd sets a property on the type with this constant as @@ -20,7 +20,9 @@ export const NG_FACTORY_DEF = getClosureSafeProperty({ɵfac: getClosureSafePrope * bloom filter bit for DI. */ // TODO(misko): This is wrong. The NG_ELEMENT_ID should never be minified. -export const NG_ELEMENT_ID = getClosureSafeProperty({__NG_ELEMENT_ID__: getClosureSafeProperty}); +export const NG_ELEMENT_ID: string = getClosureSafeProperty({ + __NG_ELEMENT_ID__: getClosureSafeProperty, +}); /** * The `NG_ENV_ID` field on a DI token indicates special processing in the `EnvironmentInjector`: @@ -30,4 +32,4 @@ export const NG_ELEMENT_ID = getClosureSafeProperty({__NG_ELEMENT_ID__: getClosu * This particular retrieval of DI tokens is mostly done to eliminate circular dependencies and * improve tree-shaking. */ -export const NG_ENV_ID = getClosureSafeProperty({__NG_ENV_ID__: getClosureSafeProperty}); +export const NG_ENV_ID: string = getClosureSafeProperty({__NG_ENV_ID__: getClosureSafeProperty}); diff --git a/packages/core/src/render3/reactivity/signal.ts b/packages/core/src/render3/reactivity/signal.ts index b62f89ecce7..10fad915b20 100644 --- a/packages/core/src/render3/reactivity/signal.ts +++ b/packages/core/src/render3/reactivity/signal.ts @@ -18,7 +18,7 @@ import { import {isSignal, Signal, ValueEqualityFn} from './api'; /** Symbol used distinguish `WritableSignal` from other non-writable signals and functions. */ -export const ɵWRITABLE_SIGNAL = /* @__PURE__ */ Symbol('WRITABLE_SIGNAL'); +export const ɵWRITABLE_SIGNAL: unique symbol = /* @__PURE__ */ Symbol('WRITABLE_SIGNAL'); /** * A `Signal` with a value that can be mutated via a setter interface. diff --git a/packages/core/src/sanitization/html_sanitizer.ts b/packages/core/src/sanitization/html_sanitizer.ts index ab0b1377c12..e2f5a72bedb 100644 --- a/packages/core/src/sanitization/html_sanitizer.ts +++ b/packages/core/src/sanitization/html_sanitizer.ts @@ -66,7 +66,7 @@ const INLINE_ELEMENTS = merge( ), ); -export const VALID_ELEMENTS = merge( +export const VALID_ELEMENTS: {[k: string]: boolean} = merge( VOID_ELEMENTS, BLOCK_ELEMENTS, INLINE_ELEMENTS, @@ -74,7 +74,9 @@ export const VALID_ELEMENTS = merge( ); // Attributes that have href and hence need to be sanitized -export const URI_ATTRS = tagSet('background,cite,href,itemtype,longdesc,poster,src,xlink:href'); +export const URI_ATTRS: {[k: string]: boolean} = tagSet( + 'background,cite,href,itemtype,longdesc,poster,src,xlink:href', +); const HTML_ATTRS = tagSet( 'abbr,accesskey,align,alt,autoplay,axis,bgcolor,border,cellpadding,cellspacing,class,clear,color,cols,colspan,' + @@ -103,7 +105,7 @@ const ARIA_ATTRS = tagSet( // can be sanitized, but they increase security surface area without a legitimate use case, so they // are left out here. -export const VALID_ATTRS = merge(URI_ATTRS, HTML_ATTRS, ARIA_ATTRS); +export const VALID_ATTRS: {[k: string]: boolean} = merge(URI_ATTRS, HTML_ATTRS, ARIA_ATTRS); // Elements whose content should not be traversed/preserved, if the elements themselves are invalid. // diff --git a/packages/language-service/test/legacy/mock_host.ts b/packages/language-service/test/legacy/mock_host.ts index 25d1fbaddd5..857c3058fbf 100644 --- a/packages/language-service/test/legacy/mock_host.ts +++ b/packages/language-service/test/legacy/mock_host.ts @@ -31,7 +31,7 @@ const logger: ts.server.Logger = { }; export const TEST_SRCDIR = process.env['TEST_SRCDIR']!; -export const PROJECT_DIR = join( +export const PROJECT_DIR: string = join( TEST_SRCDIR, 'angular', 'packages', @@ -40,11 +40,11 @@ export const PROJECT_DIR = join( 'legacy', 'project', ); -export const TSCONFIG = join(PROJECT_DIR, 'tsconfig.json'); -export const APP_COMPONENT = join(PROJECT_DIR, 'app', 'app.component.ts'); -export const APP_MAIN = join(PROJECT_DIR, 'app', 'main.ts'); -export const PARSING_CASES = join(PROJECT_DIR, 'app', 'parsing-cases.ts'); -export const TEST_TEMPLATE = join(PROJECT_DIR, 'app', 'test.ng'); +export const TSCONFIG: string = join(PROJECT_DIR, 'tsconfig.json'); +export const APP_COMPONENT: string = join(PROJECT_DIR, 'app', 'app.component.ts'); +export const APP_MAIN: string = join(PROJECT_DIR, 'app', 'main.ts'); +export const PARSING_CASES: string = join(PROJECT_DIR, 'app', 'parsing-cases.ts'); +export const TEST_TEMPLATE: string = join(PROJECT_DIR, 'app', 'test.ng'); const NOOP_FILE_WATCHER: ts.FileWatcher = { close() {}, diff --git a/packages/platform-browser-dynamic/src/platform_providers.ts b/packages/platform-browser-dynamic/src/platform_providers.ts index 8eee1ce7b22..d854cc77a45 100644 --- a/packages/platform-browser-dynamic/src/platform_providers.ts +++ b/packages/platform-browser-dynamic/src/platform_providers.ts @@ -10,6 +10,7 @@ import { COMPILER_OPTIONS, CompilerFactory, createPlatformFactory, + PlatformRef, StaticProvider, } from '@angular/core'; import {platformBrowser} from '@angular/platform-browser'; @@ -29,8 +30,9 @@ export const INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS: StaticProvider[] = [ /** * @publicApi */ -export const platformBrowserDynamic = createPlatformFactory( - platformBrowser, - 'browserDynamic', - INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, -); +export const platformBrowserDynamic: (extraProviders?: StaticProvider[]) => PlatformRef = + createPlatformFactory( + platformBrowser, + 'browserDynamic', + INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS, + ); diff --git a/packages/platform-browser-dynamic/testing/src/testing.ts b/packages/platform-browser-dynamic/testing/src/testing.ts index 48ce0a2d45b..a7cd8cba7c1 100644 --- a/packages/platform-browser-dynamic/testing/src/testing.ts +++ b/packages/platform-browser-dynamic/testing/src/testing.ts @@ -13,10 +13,8 @@ import {BrowserTestingModule} from '@angular/platform-browser/testing'; /** * @publicApi */ -export const platformBrowserDynamicTesting = createPlatformFactory( - platformBrowserDynamic, - 'browserDynamicTesting', -); +export const platformBrowserDynamicTesting: (extraProviders?: StaticProvider[]) => PlatformRef = + createPlatformFactory(platformBrowserDynamic, 'browserDynamicTesting'); /** * NgModule for testing. diff --git a/packages/platform-browser/testing/src/browser.ts b/packages/platform-browser/testing/src/browser.ts index 243f29a691d..6fa967ff965 100644 --- a/packages/platform-browser/testing/src/browser.ts +++ b/packages/platform-browser/testing/src/browser.ts @@ -15,6 +15,7 @@ import { ɵinternalProvideZoneChangeDetection as internalProvideZoneChangeDetection, ɵChangeDetectionScheduler as ChangeDetectionScheduler, ɵChangeDetectionSchedulerImpl as ChangeDetectionSchedulerImpl, + PlatformRef, } from '@angular/core'; import {TestComponentRenderer} from '@angular/core/testing'; import {BrowserModule, platformBrowser} from '../../index'; @@ -25,7 +26,8 @@ import {DOMTestComponentRenderer} from './dom_test_component_renderer'; * * @publicApi */ -export const platformBrowserTesting = createPlatformFactory(platformBrowser, 'browserTesting'); +export const platformBrowserTesting: (extraProviders?: StaticProvider[]) => PlatformRef = + createPlatformFactory(platformBrowser, 'browserTesting'); /** * NgModule for testing. diff --git a/packages/platform-server/test/hydration_utils.ts b/packages/platform-server/test/hydration_utils.ts index 91cac882982..f9f8a71c8bf 100644 --- a/packages/platform-server/test/hydration_utils.ts +++ b/packages/platform-server/test/hydration_utils.ts @@ -42,7 +42,7 @@ export const EMPTY_TEXT_NODE_COMMENT = 'ngetn'; export const TEXT_NODE_SEPARATOR_COMMENT = 'ngtns'; export const SKIP_HYDRATION_ATTR_NAME = 'ngSkipHydration'; -export const SKIP_HYDRATION_ATTR_NAME_LOWER_CASE = SKIP_HYDRATION_ATTR_NAME.toLowerCase(); +export const SKIP_HYDRATION_ATTR_NAME_LOWER_CASE: string = SKIP_HYDRATION_ATTR_NAME.toLowerCase(); export const TRANSFER_STATE_TOKEN_ID = '__nghData__'; diff --git a/packages/platform-server/testing/src/server.ts b/packages/platform-server/testing/src/server.ts index 3845ef48728..ac397d32080 100644 --- a/packages/platform-server/testing/src/server.ts +++ b/packages/platform-server/testing/src/server.ts @@ -6,7 +6,13 @@ * found in the LICENSE file at https://angular.dev/license */ -import {createPlatformFactory, NgModule, platformCore, StaticProvider} from '@angular/core'; +import { + createPlatformFactory, + NgModule, + platformCore, + PlatformRef, + StaticProvider, +} from '@angular/core'; import {ɵINTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS as INTERNAL_BROWSER_DYNAMIC_PLATFORM_PROVIDERS} from '@angular/platform-browser-dynamic'; import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing'; import { @@ -25,11 +31,12 @@ const INTERNAL_SERVER_DYNAMIC_PLATFORM_TESTING_PROVIDERS: StaticProvider[] = [ * @publicApi * @deprecated from v20.0.0, use e2e testing to verify SSR behavior. */ -export const platformServerTesting = createPlatformFactory( - platformCore, - 'serverTesting', - INTERNAL_SERVER_DYNAMIC_PLATFORM_TESTING_PROVIDERS, -); +export const platformServerTesting: (extraProviders?: StaticProvider[]) => PlatformRef = + createPlatformFactory( + platformCore, + 'serverTesting', + INTERNAL_SERVER_DYNAMIC_PLATFORM_TESTING_PROVIDERS, + ); /** * NgModule for testing. diff --git a/packages/router/src/shared.ts b/packages/router/src/shared.ts index 0cfc5924ecf..23ec9aa8c5e 100644 --- a/packages/router/src/shared.ts +++ b/packages/router/src/shared.ts @@ -21,7 +21,7 @@ export const PRIMARY_OUTLET = 'primary'; * static string or `Route.resolve` if anything else. This allows us to reuse the existing route * data/resolvers to support the title feature without new instrumentation in the `Router` pipeline. */ -export const RouteTitleKey = /* @__PURE__ */ Symbol('RouteTitle'); +export const RouteTitleKey: unique symbol = /* @__PURE__ */ Symbol('RouteTitle'); /** * A collection of matrix and query URL parameters. diff --git a/packages/upgrade/src/common/test/helpers/common_test_helpers.ts b/packages/upgrade/src/common/test/helpers/common_test_helpers.ts index 4737d55ee89..8534040dcf0 100644 --- a/packages/upgrade/src/common/test/helpers/common_test_helpers.ts +++ b/packages/upgrade/src/common/test/helpers/common_test_helpers.ts @@ -176,4 +176,5 @@ export function nodes(html: string) { return Array.prototype.slice.call(div.childNodes); } -export const withEachNg1Version = createWithEachNg1VersionFn(setAngularJSGlobal); +export const withEachNg1Version: (specSuite: () => void) => void = + createWithEachNg1VersionFn(setAngularJSGlobal); diff --git a/scripts/benchmarks/utils.mts b/scripts/benchmarks/utils.mts index 4ee95fcfa3d..52710a5d6e9 100644 --- a/scripts/benchmarks/utils.mts +++ b/scripts/benchmarks/utils.mts @@ -14,7 +14,7 @@ import url from 'url'; const scriptDir = path.dirname(url.fileURLToPath(import.meta.url)); /** Absolute disk path to the project directory. */ -export const projectDir = path.join(scriptDir, '../..'); +export const projectDir: string = path.join(scriptDir, '../..'); /** * Executes the given command, forwarding stdin, stdout and stderr while diff --git a/scripts/build/package-builder.mts b/scripts/build/package-builder.mts index 2af378825fa..440e3e6e3a5 100644 --- a/scripts/build/package-builder.mts +++ b/scripts/build/package-builder.mts @@ -16,7 +16,7 @@ import sh from 'shelljs'; sh.set('-e'); /** Path to the project directory. */ -export const projectDir = join(dirname(fileURLToPath(import.meta.url)), '../..'); +export const projectDir: string = join(dirname(fileURLToPath(import.meta.url)), '../..'); /** Command that runs Bazel. */ export const bazelCmd = process.env.BAZEL || `yarn -s bazel`; @@ -56,7 +56,7 @@ export function performDefaultSnapshotBuild(): BuiltPackage[] { function buildReleasePackages( distPath: string, isSnapshotBuild: boolean, - additionalTargets: string[] = [] + additionalTargets: string[] = [], ): BuiltPackage[] { console.info('######################################'); console.info(' Building release packages...'); @@ -120,7 +120,7 @@ function getPackageNamesOfTargets(targets: string[]): string[] { if (matches === null) { throw Error( `Found Bazel target with "${releaseTargetTag}" tag, but could not ` + - `determine release output name: ${targetName}` + `determine release output name: ${targetName}`, ); } return matches[1]; diff --git a/tools/tslint/noExportedInferredCallTypeRule.ts b/tools/tslint/noExportedInferredCallTypeRule.ts new file mode 100644 index 00000000000..8057124ec09 --- /dev/null +++ b/tools/tslint/noExportedInferredCallTypeRule.ts @@ -0,0 +1,57 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import {Replacement, RuleFailure} from 'tslint/lib'; +import {AbstractRule, TypedRule} from 'tslint/lib/rules'; +import {Rule as TypedefRule} from 'tslint/lib/rules/typedefRule'; +import ts from 'typescript'; + +/** + * Rule that ensures ("best effort") that exported constants are having + * an explicit type if they would otherwise rely on a synthetically inserted + * type that is inferred from a function call. E.g. + * + * ```ts + * export const myLoader = createImageLoader(); // Wrong! + * export const myLoader: ImageLoader = createImageLoader(); // Correct! + * ``` + */ +export class Rule extends TypedRule { + override applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] { + const checker = program.getTypeChecker(); + + return this.applyWithFunction(sourceFile, (ctx) => { + for (const st of sourceFile.statements) { + if ( + !ts.isVariableStatement(st) || + !(st.modifiers ?? []).some((s) => s.kind === ts.SyntaxKind.ExportKeyword) + ) { + continue; + } + + for (const decl of st.declarationList.declarations) { + if ( + decl.initializer !== undefined && + ts.isCallExpression(decl.initializer) && + decl.type === undefined + ) { + const inferredType = checker.getTypeAtLocation(decl.name); + const typeStr = checker.typeToString(inferredType, decl); + + ctx.addFailureAtNode( + decl, + 'No explicit type. Inferred types can cause unexpected issues. ' + + 'Please add an explicit type.', + Replacement.appendText(decl.name.end, `: ${typeStr}`), + ); + } + } + } + }); + } +} diff --git a/tslint.json b/tslint.json index e498369e72e..ec8c22c202e 100644 --- a/tslint.json +++ b/tslint.json @@ -11,6 +11,7 @@ // that rules written in TypeScript can be loaded without needing to be transpiled. "ts-node-loader": true, // Custom rules written in TypeScript. + "no-exported-inferred-call-type": true, "require-internal-with-underscore": true, "no-implicit-override-abstract": true, "validate-import-for-esm-cjs-interop": [ @@ -77,7 +78,10 @@ "name": ["*", "getMutableClone"], "message": "Use a ts.factory.update* or ts.factory.create* method instead." }, - {"name": ["performance", "mark"], "message": "`performance` methods aren't not fully supported in all environments like JSDOM and Cloudflare workers. Use 'performanceMark' from '@angular/core' instead."} + { + "name": ["performance", "mark"], + "message": "`performance` methods aren't not fully supported in all environments like JSDOM and Cloudflare workers. Use 'performanceMark' from '@angular/core' instead." + } ] }, "jsRules": {